Top Tree 模板
Sone1,AAAT。
#include <iostream>
#include <vector>
#include <cassert>
#define UP(i,s,e) for(auto i=s; i<e; ++i)
using std::cin; using std::cout;
constexpr int N = 1e5, M = 1e5;
namespace TopTree{ // }{{{
struct Modify_tag{
int val; bool ismodi;
Modify_tag(){}
Modify_tag(int v, bool t):val(v), ismodi(t){}
bool is_identity(){ return !val && !ismodi; }
Modify_tag &operator>>=(Modify_tag b){
if(b.ismodi) *this = b;
else val += b.val;
return *this;
}
};
struct Info{
int mn, mx, sum;
int siz;
bool is_identity(){ return siz == 0; }
Info(){}
Info(int x):mn(x), mx(x), sum(x), siz(1){}
Info &apply(Modify_tag mo){
if(!mo.val && !mo.ismodi) return *this;
if(siz == 0) return *this;
if(mo.ismodi){
mn = mx = sum = mo.val;
sum *= siz;
} else {
mn += mo.val; mx += mo.val;
sum += mo.val * siz;
}
return *this;
}
};
using NT = enum { RAKE, COMPRESS };
struct Node{
Node *fa;
Node *ls, *ms, *rs;
NT typ;
int val;
Info hinfo, linfo; // light not includes heavy
Modify_tag hmodi, lmodi;
bool rev;
Node &addlmodi(Modify_tag);
Node &addhmodi(Modify_tag);
} nil_, *const nil = &nil_, nds[N*2];
int nodcnt = 0;
std::vector<int> rubbish;
Node &Node::addlmodi(Modify_tag lm){lmodi >>= lm; return *this; }
Node &Node::addhmodi(Modify_tag hm){hmodi >>= hm; return *this; }
Node *nnod(){
if(rubbish.empty()) return nds+nodcnt++;
Node *p = nds + rubbish.back();
rubbish.pop_back();
return p;
}
Node *mknode(){ Node *p = nnod(); p->hmodi = p->lmodi = Modify_tag(0, 0); return p;}
void erase(Node *x){ rubbish.push_back(x-nds); }
void flip(Node *x){ if(x != nil) x->rev ^= 1; }
void pushrev(Node *x){
if(x == nil || x->typ == RAKE) return;
if(!x->rev) return;
std::swap(x->ls, x->rs);
x->rev ^= 1;
flip(x->ls);
flip(x->rs);
}
Info operator+(Info a, Info b){
if(a.is_identity() || b.is_identity()) return a.is_identity() ? b : a;
Info ret;
ret.mn = std::min(a.mn, b.mn);
ret.mx = std::max(a.mx, b.mx);
ret.sum = a.sum + b.sum;
ret.siz = a.siz + b.siz;
return ret;
}
void pushup(Node *x){
if(x == nil) return;
pushrev(x);
if(x->typ == RAKE){
x->linfo = (x->ls->linfo + x->ms->hinfo + x->ms->linfo + x->rs->linfo).apply(x->lmodi);
} else {
x->hinfo = (x->ls->hinfo + x->rs->hinfo + Info(x->val)).apply(x->hmodi);
x->linfo = (x->ls->linfo + x->ms->linfo + x->rs->linfo).apply(x->lmodi);
}
}
void pushdown(Node *x){
pushrev(x);
for(auto son:{x->ls, x->rs}){
if(son == nil) continue;
son->addlmodi(x->lmodi);
if(x->typ == COMPRESS) son->addhmodi(x->hmodi);
pushup(son);
}
if(x->ms != nil){
x->ms->addlmodi(x->lmodi);
if(x->typ == RAKE) x->ms->addhmodi(x->lmodi);
pushup(x->ms);
}
assert(x->typ != RAKE || x->hmodi.is_identity());
if(!x->hmodi.is_identity()){
if(x->hmodi.ismodi){
x->val = x->hmodi.val;
} else {
x->val += x->hmodi.val;
}
}
x->lmodi.val = x->lmodi.ismodi = 0;
x->hmodi.val = x->hmodi.ismodi = 0;
}
bool nroot(Node *x){ return x == x->fa->ls or x == x->fa->rs; }
bool isrs(Node *x){ return x == x->fa->rs; }
void pushdddd(Node *x){
if(nroot(x)) pushdddd(x->fa);
pushdown(x);
}
void setfa(Node *x, Node *f, int which){
if(x != nil) x->fa = f;
if(which == 0) f->ls = x;
else if(which == 1) f->rs = x;
else f->ms = x;
}
void rotate(Node *x){
if(x == nil || !nroot(x)) return;
Node *y = x->fa, *z = y->fa;
if(z != nil){
if(z->ls == y) z->ls = x;
else if(z->ms == y) z->ms = x;
else if(z->rs == y) z->rs = x;
}
if(x == y->ls){
setfa(x->rs, y, 0);
x->rs = y;
} else {
setfa(x->ls, y, 1);
x->ls = y;
}
y->fa = x; x->fa = z;
pushup(y);
pushup(x);
}
void splay(Node *x, Node *to = nil){
pushdddd(x);
for(Node *y; y = x->fa, nroot(x) && y!=to; rotate(x)){
if(y->fa != to && nroot(y)){
rotate(isrs(x) ^ isrs(y) ? x : y);
}
}
}
void unuse(Node *x){
assert(x->typ == RAKE);
setfa(x->ms, x->fa, 1);
x->ms = nil;
if(x->ls != nil){
Node *p = x->ls;
pushdown(p);
while(p->rs != nil) p = p->rs, pushdown(p);
splay(p, x);
setfa(x->rs, p, 1);
setfa(p, x->fa, 2);
pushup(p);
pushup(x->fa);
} else {
setfa(x->rs, x->fa, 2);
}
erase(x);
}
void splice(Node *x){
assert(x->typ == RAKE);
splay(x);
Node *y = x->fa;
splay(y);
pushdown(x);
if(y->rs != nil){
std::swap(x->ms->fa, y->rs->fa);
std::swap(x->ms, y->rs);
pushup(x);
} else {
unuse(x);
}
pushup(y);
}
void access(Node *x){
splay(x);
if(x->rs != nil){
Node *y = mknode();
y->val = 0;
y->rev = 0;
setfa(x->ms, y, 0);
setfa(x->rs, y, 2); x->rs = nil;
setfa(y, x, 2);
y->rs = nil;
y->typ = RAKE;
pushup(y);
pushup(x);
}
Node *p = x;
while(p->fa != nil){
splice(p->fa);
p = p->fa;
pushup(p);
}
splay(x);
}
void mkroot(Node *x){ access(x); flip(x); }
void expose(Node *x, Node *y){ mkroot(x); access(y); }
Node *findrt(Node *x){
access(x);
pushdown(x);
while(x->ls != nil) x = x->ls, pushdown(x);
splay(x);
return x;
}
void link(Node *x, Node *y){
//if(findrt(x) == findrt(y)) return;
access(x);
mkroot(y);
setfa(y, x, 1);
pushup(x);
}
void cut(Node *x, Node *y){
expose(x, y);
if(y->ls != x || x->rs != nil) return;
x->fa = y->ls = nil;
pushup(y);
}
} // {}}}
namespace m{ // }{{{
int in, iq;
using TopTree::Node;
Node *ndid[N];
int nowrt;
std::vector<std::pair<int, int>> tre;
void check(){
UP(i, 0, in){
for(auto son:{ndid[i]->ls, ndid[i]->ms, ndid[i]->rs}){
if(son == TopTree::nil) return;
if(son->fa != ndid[i]) throw 114514;
if(son == ndid[i]->fa) throw "WTF";
}
}
}
void get_graph(Node *p = ndid[0], Node *from = ndid[0]){
for(Node *x:{p->ls, p->ms, p->rs}){
if(x == TopTree::nil) continue;
std::cerr << x-ndid[0] << " " << p-ndid[0] << " " << (x==p->ms ? 2 : TopTree::isrs(x)) << '\t';
if(x != from) get_graph(x, p);
}
if(p->fa != TopTree::nil && from != p->fa) get_graph(p->fa, p);
}
void work(){
cin >> in >> iq;
UP(i, 0, in-1){
int iu, iv; cin >> iu >> iv; iu--, iv--;
tre.push_back({iu, iv});
}
UP(i, 0, in){
int x; cin >> x;
Node *p = TopTree::mknode();
p->ls = p->ms = p->rs = p->fa = TopTree::nil;
p->val = x;
p->typ = TopTree::COMPRESS;
p->rev = false;
TopTree::pushup(p);
ndid[i] = p;
}
cin >> nowrt; nowrt--;
for(auto &i:tre){
TopTree::link(ndid[i.first], ndid[i.second]);
}
tre.clear(); tre.shrink_to_fit();
UP(i, 0, iq){
int op, x, y, z, ans;
cin >> op;
switch(op){
case 0:
cin >> x >> y; x--;
TopTree::expose(ndid[nowrt], ndid[x]);
if(ndid[x]->ms != TopTree::nil){
ndid[x]->ms->addlmodi(TopTree::Modify_tag(y, 1));
TopTree::pushup(ndid[x]->ms);
}
ndid[x]->val = y;
TopTree::pushup(ndid[x]);
break;
case 1:
cin >> x; x--;
nowrt = x;
break;
case 2:
cin >> x >> y >> z; x--, y--;
TopTree::expose(ndid[x], ndid[y]);
ndid[y]->addhmodi(TopTree::Modify_tag(z, 1));
TopTree::pushup(ndid[y]);
break;
case 3:
cin >> x; x--;
TopTree::expose(ndid[nowrt], ndid[x]);
ans = ndid[x]->val;
if(ndid[x]->ms != TopTree::nil){
ans = std::min(ans, ndid[x]->ms->linfo.mn);
}
cout << ans << '\n';
break;
case 4:
cin >> x; x--;
TopTree::expose(ndid[nowrt], ndid[x]);
ans = ndid[x]->val;
if(ndid[x]->ms != TopTree::nil){
ans = std::max(ans, ndid[x]->ms->linfo.mx);
}
cout << ans << '\n';
break;
case 5:
cin >> x >> y; x--;
TopTree::expose(ndid[nowrt], ndid[x]);
ndid[x]->val += y;
if(ndid[x]->ms != TopTree::nil){
ndid[x]->ms->addlmodi(TopTree::Modify_tag(y, 0));
TopTree::pushup(ndid[x]->ms);
}
TopTree::pushup(ndid[x]);
break;
case 6:
cin >> x >> y >> z; x--, y--;
TopTree::expose(ndid[x], ndid[y]);
ndid[y]->addhmodi(TopTree::Modify_tag(z, 0));
TopTree::pushup(ndid[y]);
break;
case 7:
cin >> x >> y; x--, y--;
TopTree::expose(ndid[x], ndid[y]);
cout << ndid[y]->hinfo.mn << '\n';
break;
case 8:
cin >> x >> y; x--, y--;
TopTree::expose(ndid[x], ndid[y]);
cout << ndid[y]->hinfo.mx << '\n';
break;
case 9:
cin >> x >> y; x--, y--;
if(x == y) break;
TopTree::expose(ndid[nowrt], ndid[x]);
if(1){
TopTree::pushrev(ndid[x]);
Node *p = ndid[x]->ls;
if(p == TopTree::nil) break;
for(; TopTree::pushrev(p), p->rs != TopTree::nil; p = p->rs){;}
TopTree::cut(ndid[x], p);
if(TopTree::findrt(ndid[x]) == TopTree::findrt(ndid[y])){
TopTree::link(ndid[x], p);
} else {
TopTree::link(ndid[x], ndid[y]);
}
}
break;
case 10:
cin >> x >> y; x--, y--;
TopTree::expose(ndid[x], ndid[y]);
cout << ndid[y]->hinfo.sum << '\n';
break;
case 11:
cin >> x; x--;
TopTree::expose(ndid[nowrt], ndid[x]);
ans = ndid[x]->val;
if(ndid[x]->ms != TopTree::nil) ans += ndid[x]->ms->linfo.sum;
cout << ans << '\n';
default:;
}
}
}
} // {}}}
int main(){std::ios::sync_with_stdio(0); cin.tie(0); m::work(); return 0;}