teamnote history merge
This commit is contained in:
9
2025fall/source/DS/Fenwick.cpp
Normal file
9
2025fall/source/DS/Fenwick.cpp
Normal file
@@ -0,0 +1,9 @@
|
||||
ll tree[N];
|
||||
void update(int i,ll x) {
|
||||
while(i < N) tree[i] += x, i += i&-i;
|
||||
}
|
||||
int query(int i) {
|
||||
ll s = 0;
|
||||
while(i) s += tree[i], i -= i&-i;
|
||||
return s;
|
||||
}
|
||||
47
2025fall/source/DS/LiChaoTree.cpp
Normal file
47
2025fall/source/DS/LiChaoTree.cpp
Normal file
@@ -0,0 +1,47 @@
|
||||
const ll L = 1e9+7, inf = 2*L*L+7;
|
||||
struct Line {
|
||||
ll a, b;
|
||||
ll operator()(ll x){return a*x+b;}
|
||||
Line():a(0),b(-inf){}
|
||||
Line(ll a, ll b):a(a), b(b){}
|
||||
};
|
||||
struct Node {ll l, r; Line v; Node():l(-1), r(-1), v(){}};
|
||||
using LiChao = vector<Node>;
|
||||
|
||||
// add Line v in [l, r]
|
||||
void update(LiChao& seg, Line v, ll l, ll r, ll s=-L, ll e=L, ll i=0) {
|
||||
if(e < l or r < s) return;
|
||||
if(s == e) { seg[i].v = (seg[i].v(s) > v(s))?seg[i].v:v; return; }
|
||||
|
||||
ll mid=(s+e)>>1;
|
||||
if(l <= s && e <= r) {
|
||||
Line A = seg[i].v, B = v; if(A(s) < B(s)) swap(A, B);
|
||||
if(A(e) >= B(e)) seg[i].v = A;
|
||||
else if(A(mid) >= B(mid)) {
|
||||
seg[i].v = A;
|
||||
if(seg[i].r == -1) seg[i].r = seg.size(), seg.pb(Node());
|
||||
update(seg, B, mid+1, e, mid+1, e, seg[i].r);
|
||||
}
|
||||
else {
|
||||
seg[i].v = B;
|
||||
if(seg[i].l == -1) seg[i].l = seg.size(), seg.pb(Node());
|
||||
update(seg, A, s, mid, s, mid, seg[i].l);
|
||||
}
|
||||
return;
|
||||
}
|
||||
if(seg[i].l == -1) seg[i].l = seg.size(), seg.pb(Node());
|
||||
if(seg[i].r == -1) seg[i].r = seg.size(), seg.pb(Node());
|
||||
update(seg, v, l, r, s, mid, seg[i].l);
|
||||
update(seg, v, l, r, mid+1, e, seg[i].r);
|
||||
}
|
||||
// query max_{l_i <= x <= r_i} (a_i*x + b_i)
|
||||
ll query(LiChao& seg, ll x, ll s=-L, ll e=L, ll i=0) {
|
||||
if(i == -1 or x < s or e < x) return -inf;
|
||||
if(s == e) return seg[i].v(x);
|
||||
ll mid = (s+e)>>1;
|
||||
return max({query(seg, x, s, mid, seg[i].l), query(seg, x, mid+1, e, seg[i].r), seg[i].v(x)});
|
||||
}
|
||||
|
||||
// LiChao seg(1, Node());
|
||||
// update(seg, {a, b}, l, r);
|
||||
// ll v = query(seg, x);
|
||||
37
2025fall/source/DS/PBDS.cpp
Normal file
37
2025fall/source/DS/PBDS.cpp
Normal file
@@ -0,0 +1,37 @@
|
||||
#include <bits/stdc++.h>
|
||||
#include <ext/rope>
|
||||
#include <ext/pb_ds/assoc_container.hpp>
|
||||
#include <ext/pb_ds/tree_policy.hpp>
|
||||
using namespace __gnu_pbds;
|
||||
using namespace __gnu_cxx;
|
||||
|
||||
template<typename T>
|
||||
using indexed_set = tree<T, null_type, less<T>, rb_tree_tag, tree_order_statistics_node_update>;
|
||||
|
||||
indexed_set<int> s;
|
||||
s.insert(3); s.insert(2); s.insert(3); s.insert(9); s.insert(7); //2 3 7 9
|
||||
s.insert(5); //2 3 5 7 9
|
||||
s.erase(5); //2 3 7 9
|
||||
|
||||
auto x = s.find_by_order(2); // *x : 7
|
||||
|
||||
s.order_of_key(6) // 2
|
||||
s.order_of_key(7) // 2
|
||||
s.order_of_key(8) // 3
|
||||
|
||||
/////////////////////////////////////////////////////////////
|
||||
// greater_equal <- ordered_multiset / greater <- ordered_multiset
|
||||
#define oset_greater tree<ll, null_type, greater_equal<ll>, rb_tree_tag, tree_order_statistics_node_update>
|
||||
#define oset_less tree<ll, null_type, less_equal<ll>, rb_tree_tag, tree_order_statistics_node_update>
|
||||
|
||||
void oset_m_erase(ordered_set_greater &OS, ll val){
|
||||
int index = OS.order_of_key(val);
|
||||
oset_greater::iterator it = OS.find_by_order(index);
|
||||
if(it != OS.end() && *it == val) OS.erase(it);
|
||||
}
|
||||
|
||||
|
||||
/////////////////////////////////////////////////////////////
|
||||
rope<ll> r;
|
||||
r.insert(r.size() - t, i); //r.size()-t번째 자리에 i를 삽입
|
||||
r.substr(a, b - a + 1) // a부터 (b-a+1)개 만큼을 잘라낸다. 즉, [a, b] 선택
|
||||
86
2025fall/source/DS/STBeats.cpp
Normal file
86
2025fall/source/DS/STBeats.cpp
Normal file
@@ -0,0 +1,86 @@
|
||||
const int inf = 1e9+7;
|
||||
#define data _data
|
||||
struct data{
|
||||
ll mx, mx_cnt, mx2, sum;
|
||||
|
||||
constexpr data(ll m):mx(m), mx_cnt(1), mx2(-inf), sum(m) {}
|
||||
constexpr data(ll mx, ll mx_cnt, ll mx2, ll sum):mx(mx), mx_cnt(mx_cnt), mx2(mx2), sum(sum) {}
|
||||
};
|
||||
data join(data A, data B)
|
||||
{
|
||||
if(A.mx == B.mx)
|
||||
return {A.mx, A.mx_cnt+B.mx_cnt, max(A.mx2, B.mx2), A.sum+B.sum};
|
||||
if(A.mx < B.mx) swap(A, B);
|
||||
return {A.mx, A.mx_cnt, max(A.mx2, B.mx), A.sum+B.sum};
|
||||
}
|
||||
using Seg = vector<data>;
|
||||
|
||||
void init(Seg& seg, int i, int s, int e, ll* A)
|
||||
{
|
||||
if(s == e) { seg[i] = A[s]; return; }
|
||||
int mid = (s+e)/2;
|
||||
init(seg, i*2, s, mid, A); init(seg, i*2+1, mid+1, e, A);
|
||||
seg[i] = join(seg[i*2], seg[i*2+1]);
|
||||
}
|
||||
|
||||
void prop(Seg& seg, int i, int s, int e)
|
||||
{
|
||||
if(s == e) return;
|
||||
|
||||
for(auto t : {i*2, i*2+1}) {
|
||||
if(seg[t].mx > seg[i].mx) {
|
||||
seg[t].sum -= seg[t].mx_cnt * (seg[t].mx - seg[i].mx);
|
||||
seg[t].mx = seg[i].mx;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void update(Seg& seg, int i, int s, int e, int a, int b, ll v)
|
||||
{
|
||||
prop(seg, i, s, e);
|
||||
if(e<a || b<s || seg[i].mx <= v) return;
|
||||
if(a<=s && e<=b && seg[i].mx2 < v)
|
||||
{
|
||||
seg[i].sum -= seg[i].mx_cnt * (seg[i].mx - v);
|
||||
seg[i].mx = v;
|
||||
prop(seg, i, s, e);
|
||||
return;
|
||||
}
|
||||
|
||||
int mid = (s+e)/2;
|
||||
update(seg, i*2, s, mid, a, b, v);
|
||||
update(seg, i*2+1, mid+1, e, a, b, v);
|
||||
|
||||
seg[i] = join(seg[i*2], seg[i*2+1]);
|
||||
}
|
||||
|
||||
ll querymax(Seg& seg, int i, int s, int e, int a, int b)
|
||||
{
|
||||
prop(seg, i, s, e);
|
||||
if(e<a || b<s) return -inf;
|
||||
if(a<=s && e<=b) return seg[i].mx;
|
||||
|
||||
int mid = (s+e)/2;
|
||||
return max(querymax(seg, i*2, s, mid, a, b), querymax(seg, i*2+1, mid+1, e, a, b));
|
||||
}
|
||||
|
||||
ll querysum(Seg& seg, int i, int s, int e, int a, int b)
|
||||
{
|
||||
prop(seg, i, s, e);
|
||||
if(e<a || b<s) return 0;
|
||||
if(a<=s && e<=b) return seg[i].sum;
|
||||
|
||||
int mid = (s+e)/2;
|
||||
return querysum(seg, i*2, s, mid, a, b)+querysum(seg, i*2+1, mid+1, e, a, b);
|
||||
}
|
||||
|
||||
const int N = 1e6+7;
|
||||
ll A[N];
|
||||
|
||||
getint(n); get A;
|
||||
Seg s(4*n, 0); init(s, 1, 1, n, A);
|
||||
|
||||
// A[i] = min(A[i], x) for l <= i <= r
|
||||
update(s, 1, 1, n, l, r, x);
|
||||
// summation query, max query
|
||||
querysum(s, 1, 1, n, l, r), querymax(s, 1, 1, n, l, r);
|
||||
36
2025fall/source/DS/SegmentTree.cpp
Normal file
36
2025fall/source/DS/SegmentTree.cpp
Normal file
@@ -0,0 +1,36 @@
|
||||
struct Data{
|
||||
ll sum, lazy;
|
||||
constexpr Data(ll m):sum(m), lazy(){}
|
||||
constexpr Data(ll sum, ll lazy):sum(sum), lazy(lazy){}
|
||||
};
|
||||
Data join(Data A, Data B) {return A.sum+B.sum;}
|
||||
using Seg = vector<Data>;
|
||||
|
||||
void init(Seg& seg, int i, int s, int e, ll *A) {
|
||||
if(s == e) {seg[i] = A[s]; return;}
|
||||
int mid = (s+e)>>1;
|
||||
init(seg, i*2, s, mid, A); init(seg, i*2+1, mid+1, e, A);
|
||||
seg[i] = join(seg[i*2], seg[i*2+1]);
|
||||
}
|
||||
void prop(Seg& seg, int i, int s, int e) {
|
||||
seg[i].sum += seg[i].lazy * (e-s+1);
|
||||
if(s != e) for(auto t:{i*2, i*2+1}) seg[t].lazy += seg[i].lazy;
|
||||
seg[i].lazy = 0;
|
||||
}
|
||||
|
||||
void update(Seg& seg, int i, int s, int e, int a, int b, ll v) {
|
||||
prop(seg, i, s, e);
|
||||
if(e<a||b<s) return;
|
||||
if(a<=s&&e<=b) {seg[i].lazy+=v; prop(seg, i, s, e); return;}
|
||||
int mid = (s+e)>>1;
|
||||
update(seg, i*2, s, mid, a, b, v); update(seg, i*2+1, mid+1, e, a, b, v);
|
||||
seg[i] = join(seg[i*2], seg[i*2+1]);
|
||||
}
|
||||
|
||||
ll query(Seg& seg, int i, int s, int e, int a, int b) {
|
||||
prop(seg, i, s, e);
|
||||
if(e<a||b<s) return 0;
|
||||
if(a<=s&&e<=b) return seg[i].sum;
|
||||
int mid = (s+e)>>1;
|
||||
return query(seg, i*2, s, mid, a, b) + query(seg, i*2+1, mid+1, e, a, b);
|
||||
}
|
||||
160
2025fall/source/DS/SegmentTree_GMS.cpp
Normal file
160
2025fall/source/DS/SegmentTree_GMS.cpp
Normal file
@@ -0,0 +1,160 @@
|
||||
namespace GMS
|
||||
{
|
||||
template<typename D, D (*join)(D,D), D _e>
|
||||
class Segtree {
|
||||
class Node {
|
||||
Node *l, *r;
|
||||
int s,e; D v;
|
||||
public:
|
||||
Node(int s, int e) :l(0), r(0), s(s), e(e), v(_e){};
|
||||
~Node(){delete l; delete r;}
|
||||
|
||||
template<typename Dini>
|
||||
friend void init(Node* node, Dini arr[] = NULL) {
|
||||
int s = node->s, e=node->e, mid=(s+e)/2;
|
||||
if(s == e) {
|
||||
node->v = D(arr?arr[s]:_e);
|
||||
return;
|
||||
}
|
||||
|
||||
node->l = new Node(s, mid);
|
||||
init(node->l, arr);
|
||||
node->r = new Node(mid+1, e);
|
||||
init(node->r, arr);
|
||||
|
||||
node->v = join(node->l->v, node->r->v);
|
||||
}
|
||||
friend D _query(Node* node, int a, int b) {
|
||||
int s=node->s, e=node->e;
|
||||
if(a <= s and e <= b) return node->v;
|
||||
if(b < s or e < a) return _e;
|
||||
|
||||
return join(_query(node->l, a, b), _query(node->r, a, b));
|
||||
}
|
||||
friend void _update
|
||||
(Node* node, int i, function<D(D)> upd) {
|
||||
int s=node->s, e=node->e;
|
||||
if(i < s or e < i) return;
|
||||
if(s == e)
|
||||
{
|
||||
node->v = upd(node->v);
|
||||
return;
|
||||
}
|
||||
|
||||
_update(node->l, i, upd);
|
||||
_update(node->r, i, upd);
|
||||
|
||||
node->v = join(node->l->v, node->r->v);
|
||||
}
|
||||
};
|
||||
|
||||
Node *root;
|
||||
public:
|
||||
template<typename Dini>
|
||||
Segtree(int s,int e, Dini arr[] = NULL) {
|
||||
root = new Node(s, e);
|
||||
init(root, arr);
|
||||
}
|
||||
~Segtree(){delete root;}
|
||||
D query(int s, int e)
|
||||
{return _query(root, s, e);}
|
||||
void update(int i, function<D(D)> upd)
|
||||
{_update(root, i, upd);}
|
||||
};
|
||||
|
||||
|
||||
template<typename D, D (*join)(D,D), D _e, typename L, D (*apply)(D, L, int), L (*give)(L, L), L _l>
|
||||
class LZSegtree {
|
||||
class Node {
|
||||
Node *l, *r;
|
||||
int s,e;
|
||||
D v; L lz;
|
||||
|
||||
void prop() {
|
||||
v = apply(v, lz, e-s+1);
|
||||
if(l) l->lz = give(l->lz, lz);
|
||||
if(r) r->lz = give(r->lz, lz);
|
||||
|
||||
lz = _l;
|
||||
}
|
||||
|
||||
public:
|
||||
Node(int s, int e)
|
||||
:l(0), r(0), s(s), e(e), v(_e), lz(_l){};
|
||||
~Node(){delete l; delete r;}
|
||||
|
||||
template<typename Dini>
|
||||
friend void init(Node* node, Dini arr[] = NULL) {
|
||||
int s = node->s, e=node->e, mid=(s+e)/2;
|
||||
if(s == e)
|
||||
{
|
||||
node->v = D(arr?arr[s]:_e);
|
||||
return;
|
||||
}
|
||||
|
||||
node->l = new Node(s, mid);
|
||||
init(node->l, arr);
|
||||
node->r = new Node(mid+1, e);
|
||||
init(node->r, arr);
|
||||
|
||||
node->v = join(node->l->v, node->r->v);
|
||||
}
|
||||
friend D _query(Node* node, int a, int b) {
|
||||
node->prop();
|
||||
int s=node->s, e=node->e;
|
||||
if(a <= s and e <= b) return node->v;
|
||||
if(b < s or e < a) return _e;
|
||||
|
||||
return join(_query(node->l, a, b), _query(node->r, a, b));
|
||||
}
|
||||
friend void _update
|
||||
(Node* node, int a, int b, function<L(L)> upd){
|
||||
node->prop();
|
||||
int s=node->s, e=node->e;
|
||||
if(b < s or e < a) return;
|
||||
if(a <= s and e <= b)
|
||||
{
|
||||
node->lz = upd(node->lz);
|
||||
node->prop();
|
||||
return;
|
||||
}
|
||||
|
||||
_update(node->l, a, b, upd);
|
||||
_update(node->r, a, b, upd);
|
||||
|
||||
node->v = join(node->l->v, node->r->v);
|
||||
}
|
||||
};
|
||||
|
||||
Node *root;
|
||||
public:
|
||||
template<typename Dini>
|
||||
LZSegtree(int s,int e, Dini arr[] = NULL)
|
||||
{
|
||||
root = new Node(s, e);
|
||||
init(root, arr);
|
||||
}
|
||||
~LZSegtree(){delete root;}
|
||||
D query(int s, int e){return _query(root, s, e);}
|
||||
void update(int s, int e, function<L(L)> upd){_update(root, s, e, upd);}
|
||||
};
|
||||
} // namespace GMS
|
||||
|
||||
//////////////////////////////////////////////////////
|
||||
#define data _data
|
||||
|
||||
struct data {
|
||||
int m, m_cnt;
|
||||
constexpr data(int m):m(m), m_cnt(1){}
|
||||
constexpr data(int m, int m_cnt):m(m), m_cnt(m_cnt){}
|
||||
};
|
||||
data join(data A, data B) {
|
||||
if(A.m == B.m) return data(A.m, A.m_cnt+B.m_cnt);
|
||||
if(A.m < B.m) return A;
|
||||
else return B;
|
||||
}
|
||||
data apply(data A, int lz, int len)
|
||||
{return {A.m+lz, A.m_cnt};}
|
||||
int give(int a, int b){return a+b;}
|
||||
|
||||
using Seg = GMS::LZSegtree<data, join, {(int)1e9, 0}, int, apply, give, 0>;
|
||||
127
2025fall/source/DS/SplayTree.cpp
Normal file
127
2025fall/source/DS/SplayTree.cpp
Normal file
@@ -0,0 +1,127 @@
|
||||
struct Node
|
||||
{
|
||||
Node *p, *l, *r; int cnt; ll val;
|
||||
ll m, M, sum; ll lazy; bool flip, dum;
|
||||
Node(ll val, bool dum = false): p(0), l(0), r(0), cnt(1), val(val), m(val), M(val), sum(val), lazy(0), flip(0), dum(dum){}
|
||||
void fix(){
|
||||
cnt = 1+(l?l->cnt:0)+(r?r->cnt:0);
|
||||
sum = val+(l?l->sum:0)+(r?r->sum:0);
|
||||
m = min({val, (l?l->m:inf), (r?r->m:inf)});
|
||||
M = max({val, (l?l->M:-1), (r?r->M:-1)});
|
||||
}
|
||||
void prop(){
|
||||
if(flip){
|
||||
swap(l, r); if(l) l->flip = !l->flip; if(r) r->flip = !r->flip; flip = false;
|
||||
}
|
||||
if(lazy){
|
||||
val += lazy; sum += cnt * lazy; if(l) l->lazy += lazy; if(r) r->lazy += lazy; lazy = 0;
|
||||
}
|
||||
}
|
||||
|
||||
} *root;
|
||||
|
||||
// 자기보다 더 높은 노드를 루트로 하는 SplayTree를 조작하는 경우, 하위 SplayTree는 unvalid된다.
|
||||
struct SplayTree{
|
||||
Node *root = NULL, *rp = NULL;
|
||||
SplayTree(){}
|
||||
SplayTree(Node *rt){
|
||||
if(!rt) return;
|
||||
root = rt; rp = rt->p;
|
||||
}
|
||||
void mop(Node *node){
|
||||
if(node == root) node->prop();
|
||||
else mop(node->p);
|
||||
if(node->l) node->l->prop();
|
||||
if(node->r) node->r->prop();
|
||||
}
|
||||
|
||||
void rotate(Node *node){
|
||||
if(!root) return;
|
||||
if(node->p == rp) return;
|
||||
if(node->p->l == node){
|
||||
Node *p = node->p, *g = p->p;
|
||||
Node *a = node->l, *b = node->r, *c = p->r;
|
||||
p->l = b; if(b) b->p = p;
|
||||
p->r = c; if(c) c->p = p;
|
||||
node->l = a; if(a) a->p = node;
|
||||
node->r = p; p->p = node;
|
||||
node->p = g; if(g) (g->l == p?g->l:g->r) = node;
|
||||
p->fix(); node->fix();
|
||||
if(p == root) root = node;
|
||||
}
|
||||
else{
|
||||
Node *p = node->p, *g = p->p;
|
||||
Node *a = p->l, *b = node->l, *c = node->r;
|
||||
p->l = a; if(a) a->p = p;
|
||||
p->r = b; if(b) b->p = p;
|
||||
node->l = p; p->p = node;
|
||||
node->r = c; if(c) c->p = node;
|
||||
node->p = g; if(g) (g->l == p?g->l:g->r) = node;
|
||||
p->fix(); node->fix();
|
||||
if(p == root) root = node;
|
||||
}
|
||||
}
|
||||
|
||||
void splay(Node* node){
|
||||
if(!root) return; assert(node); mop(node);
|
||||
while(node->p != rp){
|
||||
Node *p, *g;
|
||||
p = node->p; g = p->p;
|
||||
if(g == rp) rotate(node);
|
||||
else if((p->l == node) == (g->l == p)) rotate(p), rotate(node);
|
||||
else rotate(node), rotate(node);
|
||||
}
|
||||
root = node;
|
||||
}
|
||||
|
||||
Node* insert(ll val, bool dum = false){
|
||||
if(!root) return root = new Node(val, dum);
|
||||
Node *now = root; while(now->r) now = now->r;
|
||||
Node* ret = now->r = new Node(val, dum);
|
||||
now->r->p = now; return splay(ret), ret;
|
||||
}
|
||||
|
||||
Node* find_kth(int k) { // 0-indexed
|
||||
assert(root); assert(root->cnt > k);
|
||||
Node *now = root; now->prop();
|
||||
while(true){
|
||||
while(now->l and now->l->cnt > k) now = now->l, now->prop();
|
||||
k -= now->l?now->l->cnt:0;
|
||||
if(k == 0) break;
|
||||
k--; now = now->r;
|
||||
now->prop();
|
||||
}
|
||||
return splay(now), now;
|
||||
}
|
||||
// s-1, e+1번째 노드가 항상 존재해야 한다.
|
||||
Node* gather(int s, int e){
|
||||
find_kth(e+1);
|
||||
SplayTree(root->l).find_kth(s-1);
|
||||
assert(root->l->r); return root->l->r;
|
||||
}
|
||||
void update(int i, int j, ll val){
|
||||
Node *node = gather(i, j); node->lazy += val;
|
||||
node->prop(); node->p->fix(); node->p->p->fix();
|
||||
}
|
||||
void reverse(int i, int j){
|
||||
Node *node = gather(i, j); node->flip = !node->flip;
|
||||
}
|
||||
void p_vals(){p_vals(root, 0, false);}
|
||||
void p_vals(Node* node, ll lz, bool flip){
|
||||
lz += node->lazy; flip ^= node->flip;
|
||||
if(!flip){
|
||||
if(node->l) p_vals(node->l, lz, flip);
|
||||
if(!node->dum) printf("%lld ", node->val+lz);
|
||||
if(node->r) p_vals(node->r, lz, flip);
|
||||
}
|
||||
else{
|
||||
if(node->r) p_vals(node->r, lz, flip);
|
||||
if(!node->dum) printf("%lld ", node->val+lz);
|
||||
if(node->l) p_vals(node->l, lz, flip);
|
||||
}
|
||||
}
|
||||
};
|
||||
// SplayTree sp;
|
||||
// fors(i, 0, n+1) arr[i] = sp.insert(i, i==0 or i == n+1);
|
||||
// Node* node = sp.gather(l, r); sp.reverse(l, r);
|
||||
// sp.find_kth(k); sp.splay(arr[k]);
|
||||
60
2025fall/source/DS/UF_QUndo.cpp
Normal file
60
2025fall/source/DS/UF_QUndo.cpp
Normal file
@@ -0,0 +1,60 @@
|
||||
struct dsu_pb {
|
||||
const int N;
|
||||
vi par; stack<pair<pii, pii> > s;
|
||||
|
||||
dsu_pb(int N):N(N), par(N) {
|
||||
fors(i, 0, N-1) par[i] = -1;
|
||||
}
|
||||
int root(int i) {
|
||||
if(par[i] < 0) return i;
|
||||
return root(par[i]);
|
||||
}
|
||||
bool join(int i, int j) {
|
||||
i = root(i); j = root(j);
|
||||
s.push({{i, par[i]}, {j, par[j]}});
|
||||
if(i == j) return false;
|
||||
if(-par[i] < -par[j]) swap(i, j);
|
||||
par[i] += par[j]; par[j] = i;
|
||||
return true;
|
||||
}
|
||||
|
||||
protected:
|
||||
void unjoin() {
|
||||
assert(!s.empty());
|
||||
auto [i, j] = s.top(); s.pop();
|
||||
par[i.fi] = i.se; par[j.fi] = j.se;
|
||||
}
|
||||
};
|
||||
|
||||
struct dsu_pf : public dsu_pb {
|
||||
vector<pair<bool, pii> > st; // fi==0 -> B type, fi==1 -> A type
|
||||
vector<pair<bool, pii> > tmp[2];
|
||||
int A=0, B=0;
|
||||
dsu_pf(int N):dsu_pb(N){}
|
||||
|
||||
bool join(int i, int j) {
|
||||
st.pb({0, {i, j}}); B++;
|
||||
return dsu_pb::join(i, j);
|
||||
}
|
||||
void pop_front() {
|
||||
assert(!st.empty());
|
||||
if(A == 0) {
|
||||
forr(i, B) unjoin();
|
||||
A = B; B = 0; reverse(all(st));
|
||||
for(auto &[b, p]:st) b = 1, dsu_pb::join(p.fi, p.se);
|
||||
}
|
||||
else if(st.back().fi == false) {
|
||||
tmp[st.back().fi].pb(st.back()); st.pop_back(); unjoin();
|
||||
while(tmp[0].size() != tmp[1].size() and (unsigned) A != tmp[1].size()) {
|
||||
tmp[st.back().fi].pb(st.back());
|
||||
st.pop_back();
|
||||
unjoin();
|
||||
}
|
||||
for(auto i:{0, 1}) reverse(all(tmp[i]));
|
||||
for(auto i:{0, 1}) for(auto v:tmp[i])
|
||||
st.pb(v), dsu_pb::join(v.se.fi, v.se.se);
|
||||
tmp[0].clear(); tmp[1].clear();
|
||||
}
|
||||
A--; st.pop_back(); unjoin();
|
||||
}
|
||||
};
|
||||
Reference in New Issue
Block a user