题意:
有一棵n个节点的树,每个节点有一个颜色,初始每个节点颜色不相同,且以节点1为根。定义每个点的权值为这个点到根的路径上不同颜色的个数。现在进行m次操作,每次操作为下列三种之一:
1、将x到当前根路径上的所有点染成一种新的颜色;
2、将x到当前根路径上的所有点染成一种新的颜色,并且把这个点设为新的根;
3、查询以x为根的子树中所有点权值的平均值。
分析:
首先我们观察到:
操作一
每次修改都是一种新的颜色。其实就是一次access操作。那么要统计的答案就是子树中每个点到根路径上虚边的条数+1的平均值。在access的过程中假设一个节点v要接为u的右儿子,那么u的右儿子所代表的子树整体会将权值 +1,而 v 所代表的子树整体会将权值 -1。
操作二、
由于涉及子树修改,所以lct无法维护,只能用线段树分类乱搞了。
利用dfs序的性质,设新的根为root,当前查询节点为x,那么 x 与 root 存在三种关系。
1. x==root,搞整棵树
2. root 不在 x 的子树内,直接搞**以1为根时**x的子树即可
3. root 在 x 的子树内,设 p 为 x 的亲儿子中包含 root 的节点,那么需要搞的就是整棵树去除掉 p 这棵子树的结果得到的答案了。
询问
其实就是操作二。一一对应就好了。
ps:码题愉快~~~
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int N=200100;
typedef long long ll;
int fa[N],c[N][2],rev[N],q[N];
int dep[N],a[N][21],h[N],w[N],lst[N],tmp[N];
ll sum[N*4];int tag[N*4],sz[N*4];
int n,m,tot,x,y,tm,root=1;
struct edge{int y,next;}g[N];
char s[100];
void adp(int x,int y){
g[++tot].y=y;
g[tot].next=h[x];
h[x]=tot;
}
void dfs(int x){
fa[x]=a[x][0];w[x]=++tm;
tmp[tm]=tmp[w[a[x][0]]]+1;
for (int i=h[x];i;i=g[i].next)
if (g[i].y!=a[x][0]){
dep[g[i].y]=dep[x]+1;
a[g[i].y][0]=x;
dfs(g[i].y);
}
lst[x]=tm;
}
/*----------------线段树-------------------*/
void pushup(int rt){
sum[rt]=sum[2*rt]+sum[2*rt+1];
}
void tagg(int rt,int val){
sum[rt]+=(ll)val*sz[rt];
tag[rt]+=val;
}
void pushdown(int rt){
if (tag[rt]){
tagg(2*rt,tag[rt]);
tagg(2*rt+1,tag[rt]);
tag[rt]=0;
}
}
void build(int rt,int l,int r){
if (l==r){sum[rt]=tmp[l],sz[rt]=1;return;}
int mid=(l+r)>>1;
build(2*rt,l,mid);build(2*rt+1,mid+1,r);
pushup(rt);sz[rt]=sz[2*rt]+sz[2*rt+1];
}
void change(int rt,int l,int r,int ll,int rr,int val){
if (ll>rr) return;
if (ll==l && r==rr){tagg(rt,val);return;}
pushdown(rt);
int mid=(l+r)>>1;
if (ll<=mid) change(2*rt,l,mid,ll,min(rr,mid),val);
if (rr> mid) change(2*rt+1,mid+1,r,max(mid+1,ll),rr,val);
pushup(rt);
}
void change(int rt,int k){
if (rt==root) change(1,1,n,1,n,k); else
if (w[root]>w[rt] && w[root]<=lst[rt]){
int t=root;
for (int i=20;i>=0;i--)
if ((dep[t]-dep[rt]-1)&(1<<i))
t=a[t][i];
change(1,1,n,1,w[t]-1,k);
change(1,1,n,lst[t]+1,n,k);
} else change(1,1,n,w[rt],lst[rt],k);
}
ll query(int rt,int l,int r,int ll,int rr){
if (ll>rr) return 0;
if (ll==l && r==rr) return sum[rt];
pushdown(rt);
int mid=(l+r)>>1;long long res=0;
if (ll<=mid) res+=query(2*rt,l,mid,ll,min(mid,rr));
if (rr> mid) res+=query(2*rt+1,mid+1,r,max(mid+1,ll),rr);
return res;
}
long double query(int rt){
if (rt==root) return 1.0*query(1,1,n,1,n)/n;
if (w[root]>w[rt] && w[root]<=lst[rt]){
int t=root;
for (int i=20;i>=0;i--)
if ((dep[t]-dep[rt]-1)&(1<<i))
t=a[t][i];
int size=w[t]-1+n-lst[t];
return 1.0*((query(1,1,n,1,w[t]-1)+query(1,1,n,lst[t]+1,n)))/size;
}
return 1.0*query(1,1,n,w[rt],lst[rt])/(lst[rt]-w[rt]+1);
}
/*--------------------线段树-------------------------*/
/*---------------------lct---------------------------*/
int isroot(int x){
return c[fa[x]][0]!=x && c[fa[x]][1]!=x;
}
void push_down(int x){
if (rev[x]){
rev[x]^=1;
rev[c[x][0]]^=1;
rev[c[x][1]]^=1;
swap(c[x][0],c[x][1]);
}
}
void rotate(int x){
int y=fa[x],z=fa[y];
int l,r;
if (c[fa[x]][0]==x)
l=0; else l=1;
r=l^1;
if (!isroot(y)) {
if (c[z][0]==y)
c[z][0]=x; else
c[z][1]=x;
}
fa[x]=z;fa[y]=x;
fa[c[x][r]]=y;
c[y][l]=c[x][r];
c[x][r]=y;
}
void splay(int x){
int top=0,t=x;
q[++top]=x;
while (!isroot(t)){
q[++top]=fa[t];
t=fa[t];
}
for (int i=top;i;i--)
push_down(q[i]);
while (!isroot(x)){
int y=fa[x],z=fa[y];
if (!isroot(y)) {
if ((c[z][0]==y)!=(c[y][0]==x))
rotate(x); else
rotate(y);
}
rotate(x);
}
}
int find(int x){
int t=x;push_down(x);
while (c[t][0]){
t=c[t][0];
push_down(t);
}
return t;
}
void access(int x){
int t=0;
while (x){
splay(x);
if (c[x][1]) change(find(c[x][1]),1);
c[x][1]=t;fa[c[x][1]]=x;
if (t) change(find(t),-1);
t=x;x=fa[x];
}
}
void makeroot(int x){
access(x);
splay(x);
rev[x]^=1;
root=x;
}
/*---------------------lct-----------------------*/
int main(){
freopen("a.in","r",stdin);
freopen("my.out","w",stdout);
scanf("%d%d",&n,&m);
for (int i=1;i<n;i++){
scanf("%d%d",&x,&y);
adp(x,y);adp(y,x);
}
tmp[1]=1;dfs(1);
for (int j=1;j<=20;j++)
for (int i=1;i<=n;i++)
a[i][j]=a[a[i][j-1]][j-1];
build(1,1,n);
while (m--){
scanf("%s%d",s,&x);
if (s[2]=='L')
access(x);
if (s[2]=='C')
makeroot(x);
if (s[2]=='Q')
printf("%.10Lf\n",query(x));
}
}