这题考了两遍 QAQAQAQ
第一遍还是我懵懂无知的时候,不知道换根怎么搞,就打的跟染色那题似的用LCT直接维护。
第二遍临近noi一个月的现在,LCT+dfs序线段树就可以了,但是手残打跪了。
题目抽象为这个模型
有一棵n个节点的树,每个节点有一个颜色,初始每个节点颜色不相同,且以节点1为根。定义每个点的权值为这个点到根的路径上不同颜色的个数。现在进行m次操作,每次操作为下列三种之一:
1、将x到当前根路径上的所有点染成一种新的颜色;
2、将x到当前根路径上的所有点染成一种新的颜色,并且把这个点设为新的根;
3、查询以x为根的子树中所有点权值的平均值。
好吧也不算抽象,其实这是另一个题目描述囧
第一步转换:任意一个点到根的路径上,相同的颜色必然是连续的一段,于是重新定义颜色数目为一个点到根的路径上虚边个数+1
于是操作一就是Access过程咯,就是在Access 过程中进行虚实边切换的时候,假设一个节点v要接为
这一步用LCT和dfs序线段树都可以维护。
第二步转换:我们发现换根比较棘手。。因为LCT换跟是没法维护子树的QAQ,于是我们选择在线段树上维护。
利用dfs序的性质,设新的根为root,当前查询节点为u,那么
1. x=root,查询整棵树
2. root 不在 x 的子树内,直接查询以
3.
需要注意的是“代表的子树”这个东西,需要记录一棵splay中最左和最右的节点分别是谁。
然后祝打的愉快
// by ztx
// [bzoj] 3779重组病毒
#include <cstdio>
#include <algorithm>
#define maxn 100010LL
int CH,NEG;
template <typename Tp> inline void read(Tp&ret) {
ret=NEG=0;while (CH=getchar(),CH<'!') ;
if(CH=='-')NEG=true,CH=getchar();
while(ret=ret*10+CH-'0',CH=getchar(),CH>'!') ;
if (NEG) ret=-ret;
}
typedef long long ll ;
typedef double lf ;
int n ;
/* EDGE */
struct FST { int to , next ; } e[maxn<<1] ;
int star[maxn] = {0} , tote = 1 ;
inline void AddEdge(int u,int v) { e[++tote].to=v;e[tote].next=star[u];star[u]=tote; }
inline void Link(int u,int v) { AddEdge(u,v);AddEdge(v,u); }
/* LCT */
int c[2][maxn] = {0} , fa[maxn] , left[maxn] , right[maxn] ;
bool rev[maxn] = {0} ;
#define l(o) c[0][o]
#define r(o) c[1][o]
#define f(o) fa[o]
inline bool Isrt(int x) { return !f(x) || (l(f(x))!=x && r(f(x))!=x) ; }
inline void Reverse(int x) {
rev[x] ^= 1 ;
std::swap(left[x],right[x]) ;
}
inline void Clear(int x) {
if (!x || !rev[x]) return ;
rev[x] = false ;
if (l(x)) Reverse(l(x)) ;
if (r(x)) Reverse(r(x)) ;
std::swap(l(x),r(x)) ;
}
inline void Maintain(int x) {
left[x] = right[x] = x ;
if (l(x)) left[x] = left[l(x)] ;
if (r(x)) right[x] = right[r(x)] ;
}
inline void Rot(int x,int d) {
int y = f(x) , z = f(y) ;
if (l(z)==y) l(z)=x ;
else if (r(z)==y) r(z)=x ;
f(x)=z , f(y)=x , f(c[d][x])=y ;
c[!d][y]=c[d][x] , c[d][x]=y ;
Maintain(y) ;
}
inline void Splay(int x) {
int y , z ;
Clear(x) ;
while (!Isrt(x)) {
y = f(x) , z = f(y) ;
Clear(z) , Clear(y) , Clear(x) ;
if (Isrt(y)) Rot(x,l(y)==x) ;
else if (l(z)==y) {
if (l(y)==x) Rot(y,1) ;
else Rot(x,0) ;
Rot(x,1) ;
} else {
if (r(y)==x) Rot(y,0) ;
else Rot(x,1) ;
Rot(x,0) ;
}
}
Maintain(x) ;
}
#undef l
#undef r
#undef f
/* SegmentTree */
#define maxt 400010LL
#define l(o) (o<<1)
#define r(o) (o<<1|1)
#define M (L+R>>1)
#define Left l(o),L,M
#define Right r(o),M+1,R
#define Update(o) sum[o] = sum[l(o)]+sum[r(o)]
int tott , ql , qr ;
ll val[maxn] , sum[maxt] , add[maxt] = {0} , qw , qa ;
inline void Build(int o,int L,int R) {
if (L == R) { sum[o] = val[L] ; return ; }
Build(Left) ; Build(Right) ;
Update(o) ;
}
inline void NodeAdd(int o,int L,int R,ll w) {
sum[o] += w*(R-L+1) ; add[o] += w ;
}
inline void Pushdown(int o,int L,int R) {
if (!o || !add[o]) return ;
if (l(o)) NodeAdd(Left,add[o]) ;
if (r(o)) NodeAdd(Right,add[o]) ;
add[o] = 0 ;
}
inline void Modify(int o,int L,int R) {
if (ql<=L && R<=qr) {
NodeAdd(o,L,R,qw) ;
return ;
}
Pushdown(o,L,R) ;
if (ql<=M) Modify(Left) ;
if (qr>M) Modify(Right) ;
Update(o) ;
}
inline void SegModify(int L,int R,ll w) {
if (L > R) return ;
ql = L , qr = R , qw = w ;
Modify(1,1,n) ;
}
inline void Query(int o,int L,int R) {
if (ql<=L && R<=qr) {
qa += sum[o] ; return ;
}
Pushdown(o,L,R) ;
if (ql<=M) Query(Left) ;
if (qr>M) Query(Right) ;
Update(o) ;
}
inline ll SegQuery(int L,int R) {
if (L > R) return 0 ;
ql = L , qr = R , qa = 0 ;
Query(1,1,tott) ;
return qa ;
}
#undef l
#undef r
/* ST */
#define maxk 18LL
int dep[maxn] = {0} , d[maxk][maxn] = {0} ;
inline void ST_init() {
int i , k ;
for (k = 1 ; k < maxk ; k ++ )
for (i = 1 ; i <= n ; i ++ )
d[k][i] = d[k-1][d[k-1][i]] ;
}
inline int NotSon(int u,int rt) {
int k ;
for (k = maxk-1 ; k >= 0 ; k -- )
if (dep[d[k][rt]] > dep[u]) rt = d[k][rt] ;
return rt ;
}
// DFN
int Beg[maxn] , End[maxn] ;
void dfs(int u) {
Beg[u] = ++tott ;
d[0][u] = fa[u] ;
val[tott] = val[Beg[fa[u]]]+1 ;
dep[u] = dep[fa[u]]+1 ;
left[u] = right[u] = u ;
for (int p = star[u] ; p ; p = e[p].next)
if (e[p].to != fa[u]) fa[e[p].to]=u,dfs(e[p].to) ;
End[u] = tott ;
}
//
#define l(o) c[0][o]
#define r(o) c[1][o]
int rtnow = 1 ;
inline void SubModify(int u,int w) {
if (!u) return ;
if (u == rtnow) SegModify(1,tott,w) ;
else if (Beg[u]<=Beg[rtnow] && End[rtnow]<=End[u]) {
int p = NotSon(u,rtnow) ;
SegModify(1,Beg[p]-1,w) ;
SegModify(End[p]+1,tott,w) ;
} else {
SegModify(Beg[u],End[u],w) ;
}
}
inline void Modify(int u) {
for (int v = 0 ; u ; v = u , u = fa[u]) {
Splay(u) ;
SubModify(left[v],-1) ;
SubModify(left[r(u)],1) ;
r(u) = v ;
Maintain(u) ;
}
}
inline void Query(int u) {
ll sum , siz ;
if (!u) return ;
if (u == rtnow) {
sum = SegQuery(1,n) ;
siz = n ;
} else if (Beg[u]<=Beg[rtnow] && End[rtnow]<=End[u]) {
int p = NotSon(u,rtnow) ;
sum = SegQuery(1,Beg[p]-1) + SegQuery(End[p]+1,tott) ;
siz = n-(End[p]-Beg[p]+1) ;
} else {
sum = SegQuery(Beg[u],End[u]) ;
siz = End[u]-Beg[u]+1 ;
}
printf("%.10lf\n", (lf)sum/(lf)siz) ;
}
int main() {
int m , i , cmd , u , v ;
// #define READ
#ifdef READ
freopen("c.in","r",stdin) ;
freopen("c.out","w",stdout) ;
#endif
read(n) , read(m) ;
for (i = 1 ; i < n ; i ++ ) {
read(u) , read(v) ;
Link(u,v) ;
}
val[Beg[tott=0]=0] = 0 , fa[1] = 0 ;
dfs(1) ;
Build(1,1,tott) ;
ST_init() ;
for (i = 1 ; i <= m ; i ++ ) {
while (cmd=getchar(),cmd<'!') ;
getchar(),cmd=getchar();
while (u=getchar(),u>'!') ;
read(u) ;
if (cmd == 'L') Modify(u) ;
if (cmd == 'C') {
Modify(u) ;
Splay(u) ;
Reverse(u) ;
rtnow = u ;
}
if (cmd == 'Q') Query(u) ;
}
#ifdef READ
fclose(stdin) , fclose(stdout) ;
#else
getchar() , getchar() ;
#endif
return 0 ;
}