DFS序+平衡树
刚开始在想平衡树维护树剖,发现这样并不能资瓷删点。而且好像复杂度还很劣。
然后LCT目测搞不了子树修改。
仔细观察, 一个点的答案只能贡献给所有子树里的询问,无视子树外的询问。也就是子树内和子树外是两回事,那就对一个点维护进入它的DFS序位置和从它子树出去的DFS序位置,一正一负,子树内的询问贡献一个正的,子树外的询问上负的直接抵消,这样就可以直接询问前缀和了。
#include<cstdio>
#include<iostream>
#define N 300005
#define key root->ch[1]->ch[0]
#define pr(_i) cout<<#_i<<" = "<<_i<<endl
using namespace std;
namespace runzhe2000
{
typedef long long ll;
char opt[3];
int n, m, ecnt, last[N], w[N];
struct edge{int next, to;}e[N];
void addedge(int a, int b)
{
e[++ecnt] = (edge){last[a], b};
last[a] = ecnt;
}
struct node
{
node *fa, *ch[2];
ll val, sum, tag;
int base, totbase;
}mem[N], *tot, *null, *root, *pos[N][2];
node* newnode(){node *p = ++tot; *p = *null; return p;}
void init()
{
null = tot = mem;
null->fa = null->ch[0] = null->ch[1] = null;
null->val = null->sum = null->base = 0;
root = newnode(); root->ch[1] = newnode();
root->ch[1]->fa = root;
}
int type(node *p){return p->fa->ch[1] == p ? 1 : 0;}
void pushdown(node *p)
{
if(!p->tag) return;
for(int i = 0; i <= 1; i++) if(p->ch[i] != null)
{
p->ch[i]->val += p->tag;
p->ch[i]->sum += p->tag * p->ch[i]->totbase;
p->ch[i]->tag += p->tag;
}
p->tag = 0;
}
void pushup(node *p)
{
pushdown(p);
p->sum = p->val*p->base + p->ch[0]->sum + p->ch[1]->sum;
p->totbase = p->base + p->ch[0]->totbase + p->ch[1]->totbase;
}
void update(node *p)
{
if(p->fa != null)update(p->fa);
pushdown(p);
}
void rotate(node *p)
{
node *f = p->fa; int d = type(p);
(p->fa = f->fa) != null ? p->fa->ch[type(f)] = p : 0;
(f->ch[d] = p->ch[!d]) != null ? f->ch[d]->fa = f : 0;
p->ch[!d] = f, f->fa = p; pushup(f);
}
void splay(node *p, node *to = null)
{
update(p);
for(; p->fa != to; )
{
if(p->fa->fa == to) rotate(p);
else if(type(p->fa) == type(p)) rotate(p->fa), rotate(p);
else rotate(p), rotate(p);
}
pushup(p);
if(to == null) root = p;
}
void dfs(int x)
{
node *p = key = pos[x][1] = newnode();
p->val = p->sum = w[x]; p->fa = root->ch[1]; p->base = 1;
splay(p);
for(int i = last[x]; i; i = e[i].next) dfs(e[i].to);
p = key = pos[x][0] = newnode();
p->val = w[x]; p->sum = -w[x]; p->fa = root->ch[1]; p->base = -1;
splay(p);
}
node* get_l(node *p){return p->ch[0] != null ? get_l(p->ch[0]) : p;}
node* get_r(node *p){return p->ch[1] != null ? get_r(p->ch[1]) : p;}
void showtree(node *p)
{
if(p == null) return;
printf("p = %ld ch0 = %ld ch1 = %ld fa = %ld\n",p-mem,p->ch[0]-mem,p->ch[1]-mem,p->fa-mem);
showtree(p->ch[0]); showtree(p->ch[1]);
}
void fetch(node *l, node *r)
{
splay(l); node *ll = get_r(root->ch[0]);
splay(r); node *rr = get_l(root->ch[1]);
splay(ll); splay(rr,ll);
}
void main()
{
scanf("%d",&n);
for(int i = 2, f; i <= n; i++)
{
scanf("%d",&f);
addedge(f, i);
}
for(int i = 1; i <= n; i++) scanf("%d",&w[i]);
init(); dfs(1); scanf("%d",&m);
for(int i = 1; i <= m; i++)
{
scanf("%s",opt);
if(opt[0] == 'Q')
{
int d; scanf("%d",&d);
fetch(pos[1][1], pos[d][1]);
printf("%lld\n",key->sum);
}
else if(opt[0] == 'C')
{
int x, y; scanf("%d%d",&x,&y);
fetch(pos[x][1], pos[x][0]);
node *p = key; key = null;
pushup(root->ch[1]); pushup(root);
splay(pos[y][1]); node *tmp = get_l(root->ch[1]);
splay(tmp, root); key = p; p->fa = root->ch[1];
splay(key);
}
else
{
int p, q; scanf("%d%d",&p,&q);
fetch(pos[p][1], pos[p][0]);
key->tag += q; key->val += q;
splay(key);
}
}
}
}
int main()
{
runzhe2000::main();
}