• LOJ #6022. 重组病毒


    Description

    支持以下操作
    1.access一个点
    2.问一个点上面的重链的个数
    3.换根 , 并access原来的根

    Solution

    对于重链个数 , 我们在 (access) 的时候对一个点的子树进行修改 .
    换根的话 , 直接 $ mroot $就好了 , 注意要先 (mroot)(rt=x) , 因为要删去现在的根和 (x) 在原来的根下的 (lca) 以上那一段的贡献 .
    然后查询就讨论一下根在子树内和子树外就行了 .
    注意讨论修改和询问的 (x=rt) 的情况 .

    #include<bits/stdc++.h>
    using namespace std;
    typedef long long ll;
    const int N=1e5+10;
    int head[N],nxt[N*2],to[N*2],num=0,n,m,L[N],R[N],DFN=0,ch[N][2],fa[N];
    bool rev[N];ll t1[N],t2[N];int f[N][19],dep[N],rt=1;
    inline void add(int x,int t){
    	for(int i=x;i<=n;i+=(i&(-i)))t1[i]+=t,t2[i]+=x*t;
    }
    inline double qry(int x){
    	ll s1=0,s2=0;
    	for(int i=x;i;i-=(i&(-i)))s1+=t1[i],s2+=t2[i];
    	return (double)(s1*(x+1)-s2);
    }
    inline void link(int x,int y){nxt[++num]=head[x];to[num]=y;head[x]=num;}
    inline void dfs(int x,int la){
    	L[x]=++DFN;
    	for(int i=1;i<=18;i++)f[x][i]=f[f[x][i-1]][i-1];
    	for(int i=head[x],u;i;i=nxt[i]){
    		if((u=to[i])==la)continue;
    		fa[u]=f[u][0]=x;dep[u]=dep[x]+1;dfs(u,x);
    	}
    	add(L[x],1);add((R[x]=DFN)+1,-1);
    }
    inline bool isrt(int x){return ch[fa[x]][0]!=x&&ch[fa[x]][1]!=x;}
    inline void rotate(int x){
    	int y=fa[x];bool t=ch[y][1]==x;
    	ch[y][t]=ch[x][!t];fa[ch[y][t]]=y;ch[x][!t]=y;fa[x]=fa[y];
       if(!isrt(y))ch[fa[y]][ch[fa[y]][1]==y]=x;
    	fa[y]=x;
    }
    inline void Rev(int x){if(x)rev[x]^=1,swap(ch[x][0],ch[x][1]);}
    inline void pushdown(int x){if(rev[x])Rev(ch[x][0]),Rev(ch[x][1]),rev[x]=0;}
    inline void Push(int x){if(!isrt(x))Push(fa[x]);pushdown(x);}
    inline void splay(int x){
    	Push(x);
    	while(!isrt(x)){
    		int y=fa[x],p=fa[y];
    		if(isrt(y))rotate(x);
    		else if((ch[p][0]==y)==(ch[y][0]==x))rotate(y),rotate(x);
    		else rotate(x),rotate(x);
    	}
    }
    inline int lca(int x,int y){
    	for(int i=18;i>=0;i--)if(dep[f[x][i]]>dep[y])x=f[x][i];
    	return x;
    }
    inline void mdf(int x,int t){
    	if(!x)return ;
    	pushdown(x);
    	while(ch[x][0])pushdown(x),x=ch[x][0];
    	if(x==rt)add(1,t);
    	if(L[rt]<=L[x] || L[rt]>R[x])add(L[x],t),add(R[x]+1,-t);
    	else{
    		int y=lca(rt,x);
    		add(1,t);add(L[y],-t);add(R[y]+1,t);
    	}
    }
    inline double query(int x){
    	if(x==rt)return qry(n)/n;
    	if(L[rt]<=L[x] || L[rt]>R[x])return (qry(R[x])-qry(L[x]-1))/(R[x]-L[x]+1);
    	else{
    		int y=lca(rt,x);
    		return (qry(L[y]-1)+qry(n)-qry(R[y]))/(L[y]-1+n-R[y]);
    	}
    }
    inline void access(int x){
    	int y=0;
    	while(x)splay(x),mdf(ch[x][1],1),ch[x][1]=y,mdf(y,-1),x=fa[y=x];
    }
    inline void mroot(int x){access(x);splay(x);Rev(x);}
    int main(){
    	freopen("shamate.in","r",stdin);
    	freopen("shamate.out","w",stdout);
    	int x,y;
    	cin>>n>>m;
    	for(int i=1;i<n;i++){
    		scanf("%d%d",&x,&y);
    		link(x,y);link(y,x);
    	}
    	dfs(1,1);
    	char op[10];
    	while(m--){
    		scanf("%s%d",op,&x);
    		if(op[2]=='Q')printf("%.10lf
    ",query(x));
    		else if(op[2]=='L')access(x);
    		else mroot(x),rt=x;
    	}
    	return 0;
    }
    
    
  • 相关阅读:
    简单家庭记账本app开发进度四
    简单家庭记账本app开发进度三
    简单家庭记账本app开发进度二
    构建之法阅读笔记一
    寒假学习进度七
    简单家庭记账本app开发进度一
    【Java每日一题】20170328
    【Java每日一题】20170327
    【Java每日一题】20170324
    【Java每日一题】20170323
  • 原文地址:https://www.cnblogs.com/Yuzao/p/9265109.html
Copyright © 2020-2023  润新知