zoukankan      html  css  js  c++  java
  • Codeforces 482E

    一道神仙LCT题,思路清奇的一批。并且一些维护改变了我对LCT之前比较浅薄单一的认知,实在是一道启发心智的好题。同时这题因为不能迅速的维护很多状态,所以不能使用makeroot来改变树的结构,以免引起错误。所以基础模板也有别于普通模板。大部分的题解都注释在代码里了,应该还好。未完待续

    #include <iostream>
    #include <cstdio>
    #include <cmath>
    #define rep(i,a,b) for(int i=a;i<=b;i++)
    #define per(i,a,b) for(int i=a;i>=b;i--)
    #define son(p,b) tree[p].child[b]
    using namespace std;
    typedef long long ll;
    const int N=2e6+5;
    struct node{
        int child[2],fa;
        ll sum,ans,ad,de,all,size; 
        //ans 答案 ,de 虚子树大小平方和 ,ad 虚子树内部答案和 ,all 不包含虚子树内size*a[k]的和 
    	//size 所有虚子树大小和 ,sum 所有子树大小和 
    }tree[N];
    int n,m,a[N];
    //Splay part
    inline void upd(int p){
        tree[p].sum=tree[son(p,0)].sum+tree[son(p,1)].sum+tree[p].size;
    	//实子树大小的和和虚子树的和 
        tree[p].ans=tree[son(p,0)].ans+tree[son(p,1)].ans+tree[p].ad//左右实子树和虚子树答案 
        +(tree[p].size*tree[p].size-tree[p].de)*a[p]//拆开看 
    	+2LL*tree[p].size*tree[son(p,1)].sum*a[p]//右子树是原树的子孙,选虚树中的和右子树组合lca为p 
    	+2LL*tree[son(p,0)].all*(tree[p].sum-tree[son(p,0)].sum);//左子树是原树的祖先 
    	tree[p].all=tree[son(p,0)].all+tree[son(p,1)].all+tree[p].size*a[p];
    	//实子树的虚子树的答案和(实子树包含了下面所有的虚子树的答案)和自己虚子树lca为p的贡献
    	//根据定义直接得出  
    }
    inline int son_check(int p){
        return son(tree[p].fa,1)==p;
    }
    inline bool root_check(int p){
        return son(tree[p].fa,1)!=p&&son(tree[p].fa,0)!=p; 
    }
    void rotate(int p){
        int f=tree[p].fa,g=tree[f].fa,k=son_check(p);
        !root_check(f)&&(son(g,son_check(f))=p),tree[p].fa=g;
        son(f,k)=son(p,k^1),tree[son(p,k^1)].fa=f;
        son(p,k^1)=f,tree[f].fa=p;
        upd(f),upd(p);
    }
    void splay(int p){
        int u=p;
        while(!root_check(p)){
            int f=tree[p].fa;
            if(!root_check(f)) rotate(son_check(p)==son_check(f)?f:p);
            rotate(p);
        }
    }
    //Link-Cut-tree part
    inline void smodify(int p,int s,int x){
    	tree[p].size+=x*tree[s].sum;
    	tree[p].de+=x*tree[s].sum*tree[s].sum;
    	tree[p].ad+=x*tree[s].ans;
    	//p的虚子树多了(少了)s,sum->size sum^2->de ans->ad 
    }
    inline void access(int p){
        for(int x=0;p;p=tree[x=p].fa) splay(p),smodify(p,son(p,1),1),son(p,1)=x,smodify(p,son(p,1),-1),upd(p);
    }
    inline void link(int x,int y){
        access(y);splay(y);
        access(x);splay(x);
        tree[y].fa=x;
        smodify(x,y,1);upd(x);
    }
    inline void cut(int x,int y){
        access(x);splay(x);splay(y);
        tree[y].fa=0;
        smodify(x,y,-1);upd(x);
    }
    inline bool ancesstor(int x,int y){
    	access(y);splay(y);splay(x);
    	if(root_check(y)) return false;
    	return true;
    }
    int fa[N];
    int main(){
        scanf("%d",&n);
    	rep(i,2,n) scanf("%d",&fa[i]);
    	rep(i,1,n){
    		scanf("%d",&a[i]);
    		tree[i].all=tree[i].ans=a[i];
    		tree[i].sum=tree[i].size=1;
    	}
    	rep(i,2,n) link(fa[i],i);
    	access(1);splay(1);
    	int _; long double __=1LL*n*n,Ans=tree[1].ans/__;
    	printf("%0.13Lf\n",Ans);
    	scanf("%d",&_);
    	while(_--){
    		int opt,x,y;
    		scanf("%d%d%d",&opt,&x,&y);
    		if(opt==1){
    			if(!ancesstor(x,y)){
    				cut(fa[x],x);link(y,x);
    				fa[x]=y;
    			}else{
    				cut(fa[y],y);link(x,y);
    				fa[y]=x;
    			}
    			access(1);splay(1);
    			Ans=tree[1].ans/__;
    		}else{
    			access(x);splay(x);
    			a[x]=y;upd(x);
    			Ans=tree[x].ans/__;
    		}
    		printf("%0.13Lf\n",Ans);
    	}
        return 0;
    }
    
  • 相关阅读:
    hdu5360 Hiking(水题)
    hdu5348 MZL's endless loop(欧拉回路)
    hdu5351 MZL's Border(规律题,java)
    hdu5347 MZL's chemistry(打表)
    hdu5344 MZL's xor(水题)
    hdu5338 ZZX and Permutations(贪心、线段树)
    hdu 5325 Crazy Bobo (树形dp)
    hdu5323 Solve this interesting problem(爆搜)
    hdu5322 Hope(dp)
    Lightoj1009 Back to Underworld(带权并查集)
  • 原文地址:https://www.cnblogs.com/Atoner/p/13066431.html
Copyright © 2011-2022 走看看