bzoj 3779 重组病毒
sol:
题面看吐了,实际上操作就是
1.access
2.makeroot
3.查询一个点到根上有多少虚边
1. 和 2. 可以 access ,每次断掉的轻边子树 -1,新连的轻边子树 +1 ,用线段树维护一下子树即可,类似树剖套线段树的方法换根
顺便复习一下换根
1.如果当前点在根的子树里,直接加
2.如果当前点就是根,整棵树加
3.如果根在当前点的子树里,从根爬到 x 下面的一个儿子 p ,修改除 p 子树外所有点
#include<bits/stdc++.h> #define LL long long using namespace std; inline int read() { int x = 0,f = 1;char ch = getchar(); for(;!isdigit(ch);ch = getchar())if(ch == '-') f = -f; for(;isdigit(ch);ch = getchar())x = 10 * x + ch - '0'; return x * f; } const int maxn = 100010; int n,m,rt; int first[maxn],to[maxn << 1],nx[maxn << 1],cnt; inline void add(int u,int v) { to[++cnt] = v; nx[cnt] = first[u]; first[u] = cnt; } inline void ins(int u,int v){add(u,v);add(v,u);} int par[maxn][24],ind[maxn],oud[maxn],size[maxn],dep[maxn],reh[maxn],dfn; inline void dfs(int x) { size[x] = 1;ind[x] = ++dfn;reh[dfn] = dep[x]; for(int i=1;i<=23;i++)par[x][i] = par[par[x][i - 1]][i - 1]; for(int i=first[x];i;i=nx[i]) { if(to[i] == par[x][0])continue; par[to[i]][0] = x; dep[to[i]] = dep[x] + 1; dfs(to[i]);size[x] += size[to[i]]; }oud[x] = dfn; } LL seg[maxn << 2],tag[maxn << 2]; inline void pushup(int x){seg[x] = seg[x << 1] + seg[x << 1 | 1];} inline void pushdown(int x,int l,int r) { if(tag[x]) { int mid = (l + r) >> 1; tag[x << 1] += tag[x];tag[x << 1 | 1] += tag[x]; seg[x << 1] += (mid - l + 1) * tag[x];seg[x << 1 | 1] += (r - mid) * tag[x]; tag[x] = 0; } } inline void build(int x,int l,int r) { if(l == r) { seg[x] = reh[l]; return; } int mid = (l + r) >> 1; build(x << 1,l,mid);build(x << 1 | 1,mid + 1,r); pushup(x); } inline void update(int x,int l,int r,int L,int R,LL v) { if(L <= l && r <= R) { tag[x] += v; seg[x] += (r - l + 1) * v; return; } pushdown(x,l,r); int mid = (l + r) >> 1; if(L <= mid)update(x << 1,l,mid,L,R,v); if(R > mid)update(x << 1 | 1,mid + 1,r,L,R,v); pushup(x); } inline LL query(int x,int l,int r,int L,int R) { if(L <= l && r <= R)return seg[x]; int mid = (l + r) >> 1;LL ans = 0; pushdown(x,l,r); if(L <= mid)ans += query(x << 1,l,mid,L,R); if(R > mid)ans += query(x << 1 | 1,mid + 1,r,L,R); return ans; } inline int isin(int x,int rt){return ind[rt] >= ind[x] && ind[rt] <= oud[x];} inline int getson(int x,int rt) { int t = dep[x] - dep[rt] - 1; for(int i=23;~i;i--)if(t & (1 << i))x = par[x][i]; return x; } inline void Modify(int x,LL v) { if(x == rt)update(1,1,n,1,n,v); else if(isin(x,rt)) { int vn = getson(rt,x); if(ind[vn] > 1)update(1,1,n,1,ind[vn] - 1,v); if(oud[vn] < n)update(1,1,n,oud[vn] + 1,n,v); } else update(1,1,n,ind[x],oud[x],v); } inline double Query(int x) { if(x == rt)return 1.0 * query(1,1,n,1,n) / n; else if(isin(x,rt)) { double ans = 0; int vn = getson(rt,x); if(ind[vn] > 1)ans += query(1,1,n,1,ind[vn] - 1); if(oud[vn] < n)ans += query(1,1,n,oud[vn] + 1,n); return ans / (n - size[vn]); } else return (1.0 * query(1,1,n,ind[x],oud[x]) / size[x]); } #define ls ch[x][0] #define rs ch[x][1] int fa[maxn],ch[maxn][2],rev[maxn],st[maxn],top; inline int isroot(int x){return ch[fa[x]][1] != x && ch[fa[x]][0] != x;} inline void pushdown(int x) { if(rev[x]) { swap(ls,rs); rev[ls] ^= 1; rev[rs] ^= 1; rev[x] ^= 1; } } inline void rotate(int x) { int y = fa[x],z = fa[y]; int l = (ch[y][1] == x),r = l ^ 1; if(!isroot(y))ch[z][ch[z][1] == y] = x; fa[x] = z;fa[ch[x][r]] = y;fa[y] = x; ch[y][l] = ch[x][r];ch[x][r] = y; } inline void splay(int x) { st[top = 1] = x; for(int i=x;!isroot(i);i=fa[i])st[++top] = fa[i]; for(int i=top;i;i--)pushdown(st[i]); while(!isroot(x)) { int y = fa[x],z = fa[y]; if(!isroot(y)) { if(ch[z][0] == y ^ ch[y][0] == x)rotate(x); else rotate(y); } rotate(x); } } inline int fd(int x) { pushdown(x); while(ls)x = ls,pushdown(x); return x; } inline void access(int x) { for(int y=0;x;rs=y,y=x,x=fa[x]) { splay(x); int tmp = fd(rs);if(rs) Modify(tmp,1); tmp = fd(y);if(y) Modify(tmp,-1); } } inline void makeroot(int x) { access(x); splay(x); rev[x] ^= 1; rt = x; } int main() { //freopen("20.in","r",stdin); //freopen("gen.out","w",stdout); n = read(),m = read();rt = 1; for(int i=2;i<=n;i++)ins(read(),read()); dep[1] = 1;dfs(1); build(1,1,n); for(int i=1;i<=n;i++)fa[i] = par[i][0]; char opt[50]; while(m--) { scanf("%s",opt + 1);int x = read(); if(opt[3] == 'L')access(x); else if(opt[3] == 'C')makeroot(x); else printf("%.10lf\n",Query(x)); } }