传送门:https://www.lydsy.com/JudgeOnline/problem.php?id=3153。
AC这道超级工业题留念。花了我整整一个下午写代码+一个上午调代码……
题目大意:维护一棵有点权的有根树,支持:linkcut,换根,对子树/链的赋值/加/询问sum/min/max。
一看12个操作就知道是大毒瘤题。
话说前几天我们某场校内模拟赛有位学长直接搬了这题原题上去,在我们一通痛骂毒瘤之后无意中看到了这么一句话:
"对于100%的数据,都满足n,m<=1e5。为了防止某些询问输出答案过大,这里保证所有输入的值的绝对值都不超过1e3。要注意是绝对值,因为权值可能为负数。"
额……所有输入?也就是说,n,m<=1e3?喵喵喵?!
好吧原来这是良(凉)心送分(命)题(即使暴力也没有那么容易打对好吗亲)(话说这真的不是愚人节题吗)。
吐槽结束进入正题。
这题可以说是toptree的经典题,也有人倾向于叫它AAA树。
以下我以杜教的思路为基础尽可能讲明白这是个啥玩意,如果实在看不懂的话……出门右转杜教题解吧。
前置技能:lct。不会的话出门右转问度娘。
我们需要对lct进行改进来支持我们维护子树信息。
我之前做过一些没有子树修改只有维护子树信息的题(如bjoi2014大融合,https://www.luogu.org/problemnew/show/P4219),不过这题更麻烦之处就在于子树修改。
为了支持子树修改,我们需要对每个点另外维护所有的轻子树,以便支持打标记之类的操作。
同时我们还需要支持access操作中插入和删除一个轻子树的操作。
一个暴力的想法是对每个点直接建一个轻儿子的链表,不过这样会被菊花图卡掉。
于是我们想到了可以再用一个splay来维护。
每个节点有1个father和4个son(记做c[0...3]),其中c[0]和c[1]是重链splay的,c[2]和c[3]是轻子树的。
对于一棵轻子树,我们优先考虑把它直接挂在c[2]或c[3]位置。
如果挂不开了呢?这时一个骚操作来了:我们通过新建虚节点的方式来“扩充位置”。
比如我们把一个虚节点接在c[2],另一个接在c[3],再在两个虚节点的c[2]和c[3]上挂轻子树,就能容下4个轻子树了。类似地我们就能容得下更多的轻子树。注意这些虚点和底下的轻儿子本身也构成一个splay,也是可以旋转的。
于是我们已经可以往一个点的轻子树内插入节点了。每次插入时在最左侧新建一个虚点,把最左侧原来的叶子接到虚点的c[2],把虚点接到原来那个叶子的位置,再把新插入的点接到虚点的c[3],最后把虚点转上去。
那么删除呢?也不难,只要把它父亲那个虚点删掉,把它原来的兄弟接到父亲原来的位置即可。
这样我们就可以支持access操作了。
makeroot操作与普通lct一样。
link就是先把一个点makeroot再插进另一个点的轻子树里。
cut稍有不同,我们采用的是把父节点access,再把子节点从父亲的轻子树里删掉。
再说一下怎么维护信息。
每个节点分别维护实子树和虚子树的信息,其中实子树的信息就是像经典lct那样维护就行,虚子树的信息不光要算它自己的虚子树,还要把它实子树内所有点的虚子树信息也算上。再记一个all表示实子树和虚子树信息之和。
shi[x] = shi[c[0]] + shi[c[1]] + val[x]
xu[x] = all[c[2]] + all[c[3]] + xu[c[0]] + xu[c[1]]
标记也要分实标记和虚标记。其中实标记只沿着实边传递,而虚标记不仅要传向虚子树,同时也会沿着实边传递,不过不同之处在于,传向虚子树时,虚标记不仅会更新子节点的虚标记,同时也会更新它的实标记,而传向实子树只会更新虚标记。
sbj[x] -> sbj[c[0]],sbj[c[1]]
xbj[x] -> xbj[c[0]],xbj[c[1]],sbj[c[2]],sbj[c[3]],xbj[c[2]],xbj[c[3]]
于是我们就可以来做这道题了。子树操作直接将一个点access再splay,然后在它的轻子树(不要在它自身)上打虚标记。链操作就是makeroot(x),access(y),splay(x),然后直接在x上打实标记即可。
不过我们注意到在链操作时要换根,而这棵树是有根树,因此操作完别忘了对原来的根再makeroot回来。
有人或许会有疑问,在这里的换根操作不会导致子树关系变化导致子树标记传递出错吗?据我所知是不会的,大概是因为一次操作只会影响到一条链上的子树关系,而这条链在操作之前就会把标记pushdown掉,就不存在影响了。
终于到了上代码的时间!参考杜教代码折腾了一天总算搞出了这份“还看得过去”的代码:
#include<bits/stdc++.h>
using namespace std;
#define il inline
#define gc getchar()
#define pc putchar
il int in(){
int x = 0,y = 0,c = gc;
while(!isdigit(c)) y = c,c = gc;
while(isdigit(c)) x = (x << 1) + (x << 3) + (c ^ '0'),c = gc;
return y == '-' ? -x : x;
}
il void out(int q){
if(q < 0) pc('-'),q = -q;
if(q >= 10) out(q / 10);
pc(q % 10 + '0');
}
int n,m,rt,val[100010];
struct ed{
int f,t;
}e[200010];
struct xx{
int mx,mn,sm,sz;
xx(int _mx = 0,int _mn = 0,int _sm = 0,int _sz = 0){
mx = _mx;mn = _mn;sm = _sm;sz = _sz;
}
};
struct bj{
int fz,ad;
bj(int _mul = 1,int _add = 0){
fz = _mul;ad = _add;
}
bool emp(){return fz == 1 && ad == 0;}
};
xx operator + (xx u,bj v){
return !u.sz ? u : xx(u.mx * v.fz + v.ad,u.mn * v.fz + v.ad,u.sm * v.fz + v.ad * u.sz,u.sz);
}
xx operator + (xx u,xx v){
return xx(max(u.mx,v.mx),min(u.mn,v.mn),u.sm + v.sm,u.sz + v.sz);
}
bj operator + (bj u,bj v){
return bj(u.fz * v.fz,u.ad * v.fz + v.ad);
}
#define l(x) t[x].c[0]
#define r(x) t[x].c[1]
#define xl(x) t[x].c[2]
#define xr(x) t[x].c[3]
#define f(x) t[x].f
#define s(x,y) t[x].c[y]
#define ll(x) t[x].c[tp]
#define rr(x) t[x].c[tp + 1]
struct node{
int f,c[4],val;
bj sbj,xbj;
xx shi,xu,all;
bool rev,isx;
}t[2000010];
int cnt,ft,bin[2000010];
il void rv(int q){
t[q].rev ^= 1;swap(l(q),r(q));
}
il void bjshi(int q,bj w){
t[q].sbj = t[q].sbj + w;t[q].shi = t[q].shi + w;t[q].val = t[q].val * w.fz + w.ad;
t[q].all = t[q].shi + t[q].xu;
}
il void bjxu(int q,bj w,bool fg = 1){
t[q].xbj = t[q].xbj + w;t[q].all = t[q].all + w;t[q].xu = t[q].xu + w;
if(fg) bjshi(q,w);
}
il void ud(int q){
t[q].shi = t[q].xu = t[q].all = xx(-(1 << 30),1 << 30,0,0);
if(!t[q].isx) t[q].all = t[q].shi = xx(t[q].val,t[q].val,t[q].val,1);
for(int i = 0;i < 2;++i) if(s(q,i)) t[q].shi = t[q].shi + t[s(q,i)].shi,t[q].xu = t[q].xu + t[s(q,i)].xu;
for(int i = 0;i < 4;++i) if(s(q,i)) t[q].all = t[q].all + t[s(q,i)].all;
for(int i = 2;i < 4;++i) if(s(q,i)) t[q].xu = t[q].xu + t[s(q,i)].all;
}
il void ps(int q){
if(t[q].rev){
if(l(q)) rv(l(q));
if(r(q)) rv(r(q));
t[q].rev = 0;
}
if(!t[q].xbj.emp()){
for(int i = 0;i < 4;++i) if(s(q,i)) bjxu(s(q,i),t[q].xbj,i >= 2);
t[q].xbj = bj(1,0);
}
if(!t[q].sbj.emp()){
for(int i = 0;i < 2;++i) if(s(q,i)) bjshi(s(q,i),t[q].sbj);
t[q].sbj = bj(1,0);
}
}
il int son(int q,int x){
if(s(q,x)) ps(s(q,x));
return s(q,x);
}
il int fd(int q){
for(int i = 0;i < 4;++i) if(s(f(q),i) == q) return i;
return -1;
}
il void sets(int q,int w,int tp){
if(w) f(w) = q;
s(q,tp) = w;
}
il bool is(int q,int tp = 0){
if(!tp) return !f(q) || (l(f(q)) != q && r(f(q)) != q);
return !f(q) || !t[q].isx || !t[f(q)].isx;
}
void ro(int q,int tp){
if(is(q,tp)) return;
int p = f(q);
if(f(p)) sets(f(p),q,fd(p));
else f(q) = 0;
f(p) = q;
if(ll(p) == q){
ll(p) = rr(q);
rr(q) = p;
if(ll(p)) f(ll(p)) = p;
}
else{
rr(p) = ll(q);
ll(q) = p;
if(rr(p)) f(rr(p)) = p;
}
ud(p);ud(q);
}
il void gx(int q){
if(f(q)) gx(f(q));
ps(q);
}
void sp(int q,int tp = 0){
ud(q);
while(!is(q,tp)){
int p = f(q);
if(is(p,tp)) ro(q,tp);
else{
if((ll(f(p)) == p) ^ (ll(p) == q)) ro(q,tp);
else ro(p,tp);
ro(q,tp);
}
}
}
il int newd(){
int q = ft ? bin[ft--] : ++cnt;
for(int i = 0;i < 4;++i) s(q,i) = 0;f(q) = 0;
t[q].sbj = t[q].xbj = bj(1,0);
t[q].shi = t[q].xu = t[q].all = xx(-(1 << 30),1 << 30,0,0);
t[q].isx = 1;t[q].rev = t[q].val = 0;
return q;
}
il void deld(int q){bin[++ft] = q;}
void ad(int q,int w){
for(int i = 2;i < 4;++i) if(!s(w,i)){
sets(w,q,i);return;
}
int p = newd(),u;
for(u = w;t[xl(u)].isx;u = son(u,2));
sets(p,xl(u),2);sets(p,q,3);sets(u,p,2);sp(p,2);
}
void del(int q){
if(t[f(q)].isx){
sets(f(f(q)),s(f(q),5 - fd(q)),fd(f(q)));
deld(f(q));sp(f(f(q)),2);
}
else sets(f(q),0,fd(q));
f(q) = 0;
}
void ac(int q){
int u;
gx(q);sp(q);
if(r(q)){
u = r(q);r(q) = 0;ad(u,q);ud(q);
}
while(f(q)){
for(u = f(q);t[u].isx;u = f(u));
sp(u);
if(r(u)){
sets(f(q),r(u),fd(q));sp(f(q),2);
}
else del(q);
sets(u,q,1);
ud(u);q = u;
}
}
il void mk(int q){
ac(q);sp(q);rv(q);
}
il int getf(int q){
ac(q);sp(q);q = son(q,0);
while(q && r(q)) q = son(q,1);
return q;
}
il int getr(int q){
while(f(q)) q = f(q);
return q;
}
int ct(int q){
int p = getf(q);
if(p){
ac(p);sp(p);del(q);ud(p);
}
return p;
}
void lk(int q,int w){
int p = ct(q);
if(getr(q) != getr(w)) p = w;
if(p){
ac(p);sp(p);ad(q,p);ud(p);
}
}
int main(){
int i,j,op,u,v,w;
n = in();m = in();rt = 1;
for(i = 1;i < n;++i){
e[i].f = in();e[i].t = in();
}
for(i = 1;i <= n;++i){
t[++cnt].val = in();ud(cnt);
}
for(i = 1;i < n;++i){
mk(e[i].f);mk(e[i].t);lk(e[i].f,e[i].t);
}
rt = in();mk(rt);
for(i = 1;i <= m;++i){
op = in();u = in();
if(op == 1){
mk(u);rt = u;
}
else if(op == 9){
v = in();
lk(u,v);
}
else if(op == 0 || op == 3 || op == 4 || op == 5 || op == 11){
ac(u);sp(u);
if(op == 3 || op == 4 || op == 11){
int as = t[u].val;
for(j = 2;j < 4;++j) if(s(u,j)){
xx p = t[s(u,j)].all;
if(op == 3) as = min(as,p.mn);
else if(op == 4) as = max(as,p.mx);
else as += p.sm;
}
out(as);pc('\n');
}
else{
w = in();
bj p = bj(op == 5,w);
t[u].val = t[u].val * p.fz + p.ad;
for(int j = 2;j < 4;++j) if(s(u,j)) bjxu(s(u,j),p);
ud(u);
}
}
else{
v = in();
mk(u);ac(v);sp(u);
if(op == 7 || op == 8 || op == 10){
xx as = t[u].shi;
out(op == 7 ? as.mn : op == 8 ? as.mx : as.sm);pc('\n');
}
else{
w = in();
bjshi(u,bj(op == 6,w));
}
mk(rt);
}
}
return 0;
}