bzoj3786-星系探索

题目

一颗带点权的树,根为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);
		}
	}
}
posted @ 2017-04-17 20:31  permui  阅读(400)  评论(0编辑  收藏  举报