BZOJ 3779 重组病毒 ——LCT 线段树
发现操作一很像一个LCT的access的操作。
然后答案就是路径上的虚边的数量。
然后考虑维护每一个点到根节点虚边的数量,
每次断开一条偏爱路径的时候,子树的值全部+1,
连接一条偏爱路径的时候,子树的值全部-1。
然后就用线段树维护DFS序就可以了。
但是还有一个换根的操作,发现线段树不能换根,所以直接在线段树上分类讨论进行更新就可以了。
然后makeroot操作就可以换根了。
#include <map> #include <ctime> #include <cmath> #include <queue> #include <cstdio> #include <cstring> #include <iostream> #include <algorithm> using namespace std; #define F(i,j,k) for (int i=j;i<=k;++i) #define D(i,j,k) for (int i=j;i>=k;--i) #define ll long long #define maxn 200005 int data[200005]; int n,m,dfn[maxn],id[maxn],f[maxn][21],in[maxn],out[maxn]; int tim[maxn],dep[maxn]; char opt[11];int x; namespace ST{ ll sum[maxn<<3],tag[maxn<<3]; void update(int o) { sum[o]=sum[o<<1]+sum[o<<1|1]; return ; } void pushdown(int o,int l,int r) { if (tag[o]!=0) { int mid=l+r>>1; sum[o<<1]+=(mid-l+1)*tag[o]; sum[o<<1|1]+=(r-mid)*tag[o]; tag[o<<1]+=tag[o]; tag[o<<1|1]+=tag[o]; tag[o]=0; } return ; } void build(int o,int l,int r) { if (l==r) { sum[o]=data[l]; tag[l]=0; return ; } int mid=l+r>>1; build(o<<1,l,mid); build(o<<1|1,mid+1,r); update(o); return ; } void modify(int o,int l,int r,int L,int R,int f) { if (L<=l&&r<=R) { tag[o]+=f; sum[o]+=(r-l+1)*f; return ; } pushdown(o,l,r); int mid=l+r>>1; if (R<=mid) return modify(o<<1,l,mid,L,R,f),update(o); else if (L>mid) return modify(o<<1|1,mid+1,r,L,R,f),update(o); else return modify(o<<1,l,mid,L,R,f),modify(o<<1|1,mid+1,r,L,R,f),update(o); } ll querysum(int o,int l,int r,int L,int R) { if (L<=l&&r<=R) return sum[o]; pushdown(o,l,r); int mid=l+r>>1; if (R<=mid) return querysum(o<<1,l,mid,L,R); else if (L>mid) return querysum(o<<1|1,mid+1,r,L,R); else return querysum(o<<1,l,mid,L,R)+querysum(o<<1|1,mid+1,r,L,R); } int Second_LCA(int a,int b) { if (dep[a]>dep[b]) swap(a,b); int dist=dep[b]-dep[a]-1; //printf("dist %d\n",dist); D(i,20,0) if ((dist>>i)&1) b=f[b][i]; return b; } int LCA(int a,int b) { if (dep[a]>dep[b]) swap(a,b); int dist=dep[b]-dep[a]; D(i,20,0) if ((dist>>i)&1) b=f[b][i]; if (a==b) return b; D(i,20,0) if (f[b][i]!=f[a][i]) b=f[b][i],a=f[a][i]; return f[b][0]; } double query(int rt,int o) { if (o==rt) { return (1.0*querysum(1,1,n,1,n))/(1.0*n); } else if (LCA(rt,o)==rt) return (querysum(1,1,n,in[o],out[o]))/(1.0*(out[o]-in[o]+1)); else if (LCA(rt,o)==o) { int tmp=Second_LCA(rt,o); return (1.0*querysum(1,1,n,1,n)-1.0*querysum(1,1,n,in[tmp],out[tmp]))/(1.0*(n-out[tmp]+in[tmp]-1)); } else { return (1.0*querysum(1,1,n,in[o],out[o]))/(1.0*(out[o]-in[o]+1)); } } void add(int rt,int o,int f) { if (!o) return ; if (o==rt) return modify(1,1,n,1,n,f); else if (LCA(rt,o)==rt) return modify(1,1,n,in[o],out[o],f); else if (LCA(rt,o)==o) { int tmp=Second_LCA(rt,o); modify(1,1,n,1,n,f); modify(1,1,n,in[tmp],out[tmp],-f); } else return modify(1,1,n,in[o],out[o],f); } } namespace LCT{ int rev[maxn],ch[maxn][2],fa[maxn]; int sta[maxn],top,rt=1; bool isroot(int o) {return (ch[fa[o]][0]!=o)&&(ch[fa[o]][1]!=o);} void pushdown(int o) { if (rev[o]) { rev[o]^=1; rev[ch[o][0]]^=1; rev[ch[o][1]]^=1; swap(ch[o][0],ch[o][1]); } } void rot(int x) { int y=fa[x],z=fa[y],l,r; if (ch[y][0]==x) l=0; else l=1; r=l^1; if (!isroot(y)) { if (ch[z][0]==y) ch[z][0]=x; else ch[z][1]=x; } fa[x]=z; fa[y]=x; fa[ch[x][r]]=y; ch[y][l]=ch[x][r]; ch[x][r]=y; } void splay(int x) { sta[top=1]=x; for (int i=x;!isroot(i);i=fa[i]) sta[++top]=fa[i]; while (top) pushdown(sta[top--]); while (!isroot(x)) { int y=fa[x]; if (!isroot(y)) { int z=fa[y]; if (ch[y][0]==x^ch[z][0]==y) rot(x); else rot(y); } rot(x); } } int find(int x) { pushdown(x); while (ch[x][0]) x=ch[x][0],pushdown(x); return x; } void access(int x) { for (int t=0;x;t=x,x=fa[x]) { splay(x); ST::add(rt,find(ch[x][1]),1); ch[x][1]=t; ST::add(rt,find(t),-1); } } void makeroot(int x) { access(x); splay(x); rev[x]^=1; rt=x; } } namespace Graph{ int h[maxn],to[maxn],ne[maxn],en=0,tot=0; void add(int a,int b){to[en]=b;ne[en]=h[a];h[a]=en++;} void dfs(int o,int fa) { in[o]=dfn[o]=++tot; id[tot]=o; f[o][0]=fa; for (int i=h[o];i>=0;i=ne[i]) if (to[i]!=fa) dep[to[i]]=dep[o]+1,tim[to[i]]=tim[o]+1,dfs(to[i],o); out[o]=tot; } } int main() { memset(Graph::h,-1,sizeof Graph::h); scanf("%d%d",&n,&m); F(i,1,n-1) { int a,b; scanf("%d%d",&a,&b); Graph::add(a,b);Graph::add(b,a); } tim[1]=1; Graph::dfs(1,0); F(i,1,n) LCT::fa[i]=f[i][0]; F(i,1,20) F(j,1,n) f[j][i]=f[f[j][i-1]][i-1]; F(i,1,n) data[dfn[i]]=tim[i]; ST::build(1,1,n); F(i,1,m) { scanf("%s%d",opt,&x); switch(opt[2]) { case 'Q': printf("%.10lf\n",ST::query(LCT::rt,x)); break; case 'C': LCT::makeroot(x); break; case 'L': LCT::access(x); break; } } }