一开始看到子树操作想要树剖,但是仔细想想之后发现树剖没有办法维护一个点到根节点的距离,而且无法维护对应关系,后来就想到了使用dfs序,这样只要维护前缀和就可以快速求出一个点到根节点的距离,由于有换边操作,所以我们要使用splay维护,这道题要注意一个细节,就是每次想要提取出来一个区间需要先找到这个区间的前驱后继,都做完以后这题就能过啦
#include<cstdio>
#include<cstdlib>
#include<ctime>
#include<cmath>
#include<cstring>
#include<string>
#include<iostream>
#include<iomanip>
#include<algorithm>
using namespace std;
typedef long long ll;
struct splay
{
splay *fa,*ls,*rs;
ll v,sum,zsize,fsize,add_mark;
bool pr;
splay();
void push_up();
void add_v(ll val);
void push_down();
}*null=new splay(),mempool[300000],*root;
int dfsx[300000];
int in_t[300000];
int out_t[300000];
int fir[300000];
int nex[300000];
struct bian
{
int r;
}a[600000];
int topppp;
ll v[300000];
int top=0;
void dfs(int u,int fro)
{
dfsx[++top]=u;
in_t[u]=top;
for(int o=fir[u];o!=0;o=nex[o])
if(a[o].r!=fro)
dfs(a[o].r,u);
dfsx[++top]=u;
out_t[u]=top;
}
void splay :: push_up()
{
sum=ls->sum+v+rs->sum;
zsize=ls->zsize+pr+rs->zsize;
fsize=ls->fsize+(1-pr)+rs->fsize;
}
void splay :: push_down()
{
if(add_mark)
{
if(ls!=null) ls->add_v(add_mark);
if(rs!=null) rs->add_v(add_mark);
add_mark=0;
}
}
void splay :: add_v(ll val)
{
if(pr) v+=val;
else v-=val;
sum+=(zsize-fsize)*val;
add_mark+=val;
}
splay :: splay()
{
fa=ls=rs=null;
v=sum=zsize=fsize=add_mark=pr=0;
}
void right(splay *x)
{
splay *y=x->fa;
y->ls=x->rs;
x->rs->fa=y;
x->rs=y;
x->fa=y->fa;
if(y==y->fa->ls) y->fa->ls=x;
if(y==y->fa->rs) y->fa->rs=x;
y->fa=x;
y->push_up();
if(y==root) root=x;
}
void left(splay *x)
{
splay *y=x->fa;
y->rs=x->ls;
x->ls->fa=y;
x->ls=y;
x->fa=y->fa;
if(y==y->fa->ls) y->fa->ls=x;
if(y==y->fa->rs) y->fa->rs=x;
y->fa=x;
y->push_up();
if(y==root) root=x;
}
void push_down(splay *x)
{
if(x->fa!=null) push_down(x->fa);
x->push_down();
}
void splaying(splay *x,splay *goal)
{
push_down(x);
while(1)
{
splay *y=x->fa;
splay *z=y->fa;
//cout<<x<<" "<<y->rs<<endl;//<<null<<" "<<endl;
if(y==goal) break;
if(z==goal)
{
if(x==y->ls) right(x);
else left(x);
break;
}
if(x==y->ls)
{
if(y==z->ls) right(y);
right(x);
}
else if(x==y->rs)
{
if(y==z->rs) left(y);
left(x);
}
}
x->push_up();
}
splay *maketree(int l,int r)
{
if(l>r) return null;
int mid=l+r>>1;
splay *x=&mempool[mid];
if(mid==in_t[dfsx[mid]])
{
x->v=v[dfsx[mid]];
x->sum=v[dfsx[mid]];
x->pr=true;
x->zsize=1;
}
else
{
x->v=-v[dfsx[mid]];
x->sum=-v[dfsx[mid]];
x->pr=false;
x->fsize=1;
}
x->ls=maketree(l,mid-1);
x->ls->fa=x;
x->rs=maketree(mid+1,r);
x->rs->fa=x;
x->push_up();
return x;
}
splay* find_hou(splay *o)
{
if(o->ls!=null) return find_hou(o->ls);
return o;
}
splay* find_qian(splay *o)
{
if(o->rs!=null) return find_qian(o->rs);
return o;
}
ll find_ans(int x)
{
splaying(&mempool[in_t[1]],null);
splay *mid=find_qian(root->ls);
splaying(&mempool[in_t[x]],null);
splay *midd=find_hou(root->rs);
splaying(mid,null);
splaying(midd,root);
return root->rs->ls->sum;
}
void change(int x,int v)
{
splaying(&mempool[in_t[x]],null);
splay *mid=find_qian(root->ls);
splaying(&mempool[out_t[x]],null);
splay *midd=find_hou(root->rs);
splaying(mid,null);
splaying(midd,root);
root->rs->ls->add_v(v);
root->rs->push_up();
root->push_up();
}
void move_to_wz(int x,int y)
{
splaying(&mempool[in_t[x]],null);
splay *mid=find_qian(root->ls);
splaying(&mempool[out_t[x]],null);
splay *midd=find_hou(root->rs);
splaying(mid,null);
splaying(midd,root);
splay *qie=root->rs->ls;
qie->fa=null;
root->rs->ls=null;
root->rs->push_up();
root->push_up();
splaying(&mempool[in_t[y]],null);
splay *middd=find_hou(root->rs);
splaying(middd,root);
root->rs->ls=qie;
qie->fa=root->rs;
root->rs->push_up();
root->push_up();
}
void add_edge(int l,int r)
{
//cout<<l<<" "<<r<<endl;
a[++topppp].r=r;
nex[topppp]=fir[l];
fir[l]=topppp;
}
char s[10];
int main()
{
ll n,m;
scanf("%lld",&n);
for(int i=1;i<n;i++)
{
int x;
scanf("%d",&x);
add_edge(x,i+1);
}
for(int i=1;i<=n;i++) scanf("%lld",&v[i]);
dfs(1,0);
root=maketree(0,top+1);
scanf("%lld",&m);
for(int i=1;i<=m;i++)
{
scanf("%s",s);
if(s[0]=='Q')
{
int x;
scanf("%d",&x);
printf("%lld\n",find_ans(x));
}
else if(s[0]=='F')
{
ll x,val;
scanf("%lld%lld",&x,&val);
change(x,val);
}
else
{
int x,y;
scanf("%d%d",&x,&y);
move_to_wz(x,y);
}
}
}