bzoj3779-重组病毒

一颗\(n\)个点的树,初始颜色都不同,初始根为1。定义一个点到根的代价为这个点到根路径上不同颜色个数。有\(m\)个操作,分三种:

  • 将一个点到根路径上的所有点颜色改为一种新的颜色
  • 询问一个点的子树的所有点到根的代价和
  • 对点\(x\)进行操作1后把根换成\(x\)

\(n,m\le 10^5\)

分析

那个修改看着是不是很像access操作呢!换根操作之前要先access就是link-cut tree的makeroot呀!

首先,令1的深度为1,那么初始所有点的代价就是他们的深度。我们用lct来维护这个树的结构,支持换根即可。所以一切的关键都集中在了access上。

access其实就是实虚边切换的操作。注意到代价其实就是点到根路径上虚边个数+1,所以如果我们把一条实边改成虚边,那么整颗子树的答案加一,虚边改实边整个子树答案减一,用线段树维护一下dfs序就好啦。

等等!我们不是换了根吗,怎么用dfs序维护子树呢?画一画图,设当前点为\(x\),发现:

  • \(root=x\),那么就是整个树
  • \(root\)\(x\)的子树中,那么就是整棵树除去\(x\)的root那颗子树
  • 否则就是原来的子树

所以dfs序依然可以维护,只是要分情况讨论一下。

代码

#include<cstdio>
#include<cctype>
#include<vector>
#include<cstring>
#include<algorithm>
using namespace std;
typedef long long giant;
int read() {
	int 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 int maxn=1e5+10;
const int maxj=18;
int n,m,root=1,first[maxn],second[maxn],dft=0,f[maxn][maxj],dep[maxn];
struct node {
	int ch[2],fa;
	bool rev;
} t[maxn];
struct SGT {
	giant t[maxn<<2],tag[maxn<<2];
	void push(int x,int L,int mid,int R) {
		if (!tag[x]) return;
		tag[x<<1]+=tag[x],tag[x<<1|1]+=tag[x];
		t[x<<1]+=(mid-L+1)*tag[x];
		t[x<<1|1]+=(R-mid)*tag[x];
		tag[x]=0;
	}
	void add(int x,int L,int R,int l,int r,giant d) {
		if (L==l && R==r) {
			tag[x]+=d;
			t[x]+=(R-L+1)*d;
			return;
		}
		int mid=(L+R)>>1;
		push(x,L,mid,R);
		if (r<=mid) add(x<<1,L,mid,l,r,d); else 
		if (l>mid) add(x<<1|1,mid+1,R,l,r,d); else
		add(x<<1,L,mid,l,mid,d),add(x<<1|1,mid+1,R,mid+1,r,d);
		t[x]=t[x<<1]+t[x<<1|1];
	}
	void add(int l,int r,giant d) {
		if (l>r) return;
		add(1,1,n,l,r,d);
	}
	giant query(int x,int L,int R,int l,int r) {
		if (L==l && R==r) return t[x];
		int mid=(L+R)>>1;
		push(x,L,mid,R);
		if (r<=mid) return query(x<<1,L,mid,l,r); 
		if (l>mid) return query(x<<1|1,mid+1,R,l,r); else 
		return query(x<<1,L,mid,l,mid)+query(x<<1|1,mid+1,R,mid+1,r);
	}
	giant query(int l,int r) {
		if (l>r) return 0ll;
		return query(1,1,n,l,r);
	}
} sgt;
vector<int> g[maxn];
void add(int x,int y) {g[x].push_back(y);}
void dfs(int x,int fa) {
	first[x]=++dft;
	dep[x]=dep[fa]+1;
	f[x][0]=fa;
	sgt.add(first[x],first[x],dep[x]);
	for (int v:g[x]) if (v!=fa) t[v].fa=x,dfs(v,x);
	second[x]=dft;
}
int jump(int x,int y) {
	if (!y) return x;
	for (int j=0;j<maxj;++j) if ((y>>j)&1) x=f[x][j];
	return x;
}
bool insub(int x,int y) {
	return first[x]<=first[y] && first[y]<=second[x];
}
double query(int x) {
	if (root==x) {
		return (double)sgt.query(1,n)/n;
	} else if (insub(x,root)) {
		int p=jump(root,dep[root]-dep[x]-1);
		double ret=sgt.query(1,first[p]-1)+sgt.query(second[p]+1,n);
		ret/=(double)(first[p]-1+n-second[p]);
		return ret;
	} else {
		return (double)sgt.query(first[x],second[x])/(second[x]-first[x]+1);
	}
}
bool rson(int x) {
	return t[t[x].fa].ch[1]==x;
}
bool isroot(int x) {
	return !x || t[t[x].fa].ch[rson(x)]!=x;
}
void push(int x) {
	if (t[x].rev) {
		swap(t[x].ch[0],t[x].ch[1]);
		if (t[x].ch[0]) t[t[x].ch[0]].rev^=true;
		if (t[x].ch[1]) t[t[x].ch[1]].rev^=true;
		t[x].rev=false;
	}
}
void down(int x) {
	if (!isroot(x)) down(t[x].fa);
	push(x);
}
void rotate(int x) {
	int f=t[x].fa,d=rson(x),c=t[x].ch[d^1];
	if (!isroot(f)) 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[f].ch[d]=c,t[x].ch[d^1]=f;
}
void splay(int x) {
	down(x);
	while (!isroot(x)) {
		if (isroot(t[x].fa)) rotate(x); else {
			if (rson(x)==rson(t[x].fa)) rotate(t[x].fa),rotate(x); else 
			rotate(x),rotate(x);
		}
	}
}
void change(int x,giant d) {
	if (x==root) sgt.add(1,n,d); else 
	if (insub(x,root)) {
		int p=jump(root,dep[root]-dep[x]-1);
		sgt.add(1,first[p]-1,d);
		sgt.add(second[p]+1,n,d);
	} else {
		sgt.add(first[x],second[x],d);
	}
}
int left(int x) {
	for (push(x);t[x].ch[0];x=t[x].ch[0],push(x));
	return x;
}
void ace(int x) {
	for (int last=0;x;x=t[last=x].fa) {
		splay(x);
		giant tmp=sgt.query(first[x],first[x]);
		if (t[x].ch[1]) change(left(t[x].ch[1]),1);
		if (last) change(left(last),-1);
		t[x].ch[1]=last;
	}
}
void cent(int x) {
	root=x;
	splay(x);
	t[x].rev^=true;
}
int main() {
#ifndef ONLINE_JUDGE
	freopen("test.in","r",stdin);
	freopen("my.out","w",stdout);
#endif
	n=read(),m=read();
	for (int i=1;i<n;++i) {
		int x=read(),y=read();
		add(x,y),add(y,x);
	}
	dfs(1,1);
	for (int j=1;j<maxj;++j) for (int i=1;i<=n;++i) f[i][j]=f[f[i][j-1]][j-1];
	while (m--) {
		static char ord[20];
		scanf("%s",ord);
		int x=read();
		if (ord[2]=='Q') {
			double ans=query(x);
			printf("%.10lf\n",ans);
		} else {
			ace(x);
			if (ord[2]=='C') cent(x);
		}
	}
	return 0;
}
posted @ 2017-05-27 12:41  permui  阅读(714)  评论(0编辑  收藏  举报