题目
一颗带点权的树,根为1,实现下列三种操作:
- \(Q\ x\) 求点\(x\)到根的点权和
- \(C\ x\ y\) 把\(x\)的父亲换成\(y\)
\(F\ x\ y\) 把\(x\)的子树中每个点的点权点权增加\(y\)
分析
写了一半发现lct做不了,因为有子树修改。然而zwl说,由于树的形态没有改变,可以通过维护lct的一些东西解决。toptree模板题,但是不会写。于是有一个神奇方法——dfs序(欧拉序)。我们把每个点的入栈和出栈时间用一个splay维护,那么就可以很方便的修改子树(splay标记),换父亲(区间移动)。现在问题是怎么求到根的点权和。这里有一个很精妙的做法:我们把入栈时的点设为正,出栈设为负,那么欧拉序前缀和就是点到根的点权和。因为如果已经出栈了的点是不在这个点到根的链上的。这样做就很简单了。
代码
一定要记得,splay在insert的时候是要不断下传标记的。一开始就这里错了。
#include<cstdio>
#include<algorithm>
#include<cctype>
#define F(x) for (giant i=h[x],v=e[i].v;i;i=e[i].nxt,v=e[i].v)
using namespace std;
typedef long long giant;
giant read() {
giant x=0,f=1;
char c=getchar();
for (;!isdigit(c);c=getchar()) if (c=='-') f=-1;
for (;isdigit(c);c=getchar()) x=x*10+c-'0';
return x*f;
}
const giant maxn=1e5+10;
const giant inf=1e9+10;
giant val[maxn],dft=1,first[maxn],second[maxn];
struct node {
giant v,sum,fa,ch[2],sta,tag,gs,ps,ns;
bool inv;
} t[maxn<<2];
struct edge {
giant v,nxt;
} e[maxn<<1];
giant h[maxn],tot=0;
void add(giant u,giant v) {
e[++tot]=(edge){v,h[u]};
h[u]=tot;
}
giant root;
bool rson(giant x) {
return t[t[x].fa].ch[1]==x;
}
giant pos(giant x) {
giant now=x,ret=t[t[x].ch[0]].gs+1;
while (now) {
if (rson(now)) ret+=t[t[t[now].fa].ch[0]].gs+1;
now=t[now].fa;
}
return ret;
}
giant find(giant x) {
giant now=root;
while (true) {
giant tmp=t[t[now].ch[0]].gs+1;
if (x==tmp) return now; else
if (x>tmp) x-=tmp,now=t[now].ch[1]; else
if (x<tmp) now=t[now].ch[0];
}
return 0;
}
void doit(giant x,giant y) {
if (!x) return;
t[x].tag+=y;
t[x].v+=y;
t[x].sum+=(t[x].ps-t[x].ns)*y;
}
void push(giant x) {
if (!t[x].tag) return;
giant l=t[x].ch[0],r=t[x].ch[1];
if (l) doit(l,t[x].tag);
if (r) doit(r,t[x].tag);
t[x].tag=0;
}
void update(giant x) {
push(x);
t[x].gs=t[t[x].ch[0]].gs+t[t[x].ch[1]].gs+1;
t[x].ps=t[t[x].ch[0]].ps+t[t[x].ch[1]].ps+(t[x].sta==1);
t[x].ns=t[t[x].ch[0]].ns+t[t[x].ch[1]].ns+(t[x].sta==-1);
t[x].sum=t[t[x].ch[0]].sum+t[t[x].ch[1]].sum+t[x].v*t[x].sta;
}
void rotate(giant x) {
giant f=t[x].fa,d=rson(x),c=t[x].ch[d^1];
if (t[f].fa) t[t[f].fa].ch[rson(f)]=x;
if (c) t[c].fa=f;
t[x].fa=t[f].fa,t[f].fa=x,t[x].ch[d^1]=f,t[f].ch[d]=c;
update(f),update(x);
}
void down(giant x) {
if (t[x].fa) down(t[x].fa);
push(x);
}
void splay(giant x,giant d=0) {
down(x);
while (t[x].fa!=d) {
if (t[t[x].fa].fa==d) rotate(x); else {
if (rson(x)==rson(t[x].fa)) {
rotate(t[x].fa);
rotate(x);
} else {
rotate(x);
rotate(x);
}
}
}
if (!d) root=x;
}
void insert(giant p,giant x) {
if (!root) {
update(x);
t[root=x].gs=1;
return;
}
giant now=root;
while (now) {
push(now);
giant tmp=t[t[now].ch[0]].gs+1;
giant &a=t[now].ch[p>=tmp];
p-=(p>=tmp)*tmp;
if (a) now=a; else {
a=x;
t[x].fa=now;
update(x);
break;
}
}
for (;now;now=t[now].fa) update(now);
splay(x);
}
giant range(giant x,giant y) {
giant px=pos(x);
giant bf=find(px-1);
splay(bf);
giant py=pos(y);
giant af=find(py+1);
splay(af,bf);
return t[af].ch[0];
}
void dfs(giant x,giant fa) {
first[x]=++dft;
t[dft].sta=1;
t[dft].v=val[x];
insert(dft-1,dft);
F(x) if (v!=fa) dfs(v,x);
second[x]=++dft;
t[dft].sta=-1;
t[dft].v=val[x];
insert(dft-1,dft);
}
int main() {
#ifndef ONLINE_JUDGE
freopen("test.in","r",stdin);
freopen("my.out","w",stdout);
#endif
giant n=read();
for (giant i=2;i<=n;++i) {
giant x=read();
add(i,x),add(x,i);
}
for (giant i=1;i<=n;++i) val[i]=read();
insert(0,1); // because of this node, all the ids have to be increased by one.
dfs(1,0);
insert(n*2+1,n*2+2);
giant m=read();
while (m--) {
static char o[3];
scanf("%s",o);
if (o[0]=='Q') {
giant x=read();
giant now=range(2,first[x]);
printf("%lld\n",t[now].sum);
splay(now);
} else if (o[0]=='C') {
giant x=read(),y=read();
giant nx=range(first[x],second[x]);
giant f=t[nx].fa;
bool rs=rson(nx);
t[f].ch[rs]=0,t[nx].fa=0;
update(f);
insert(pos(first[y]),nx);
} else if (o[0]=='F') {
giant x=read(),y=read();
giant now=range(first[x],second[x]);
doit(now,y);
splay(now);
}
}
}