zoukankan      html  css  js  c++  java
  • LOJ558 我们的 CPU 遭到攻击

    我们的 CPU 遭到攻击

    给你一个有 (n) 个点的森林,点有黑白两种颜色,初始时所有点都是白色,森林的每条边有边权,初始时这个森林有 (m) 条边。

    对这个森林进行 (k) 次操作,操作有三种:

    • L u v w:添加一条连接 (u)(v),长度为 (w) 的边。

    • C u v:删除连接 (u)(v) 的边(保证存在)。

    • F u:反转点 (u) 的颜色(黑变白,白变黑)。

    • Q u:询问所有与 (u) 相连的黑点到 (u) 的距离之和。(相连指的是在同一连通块中

    (0le k< nle 10^5)(mle 3 imes 10^5)(|w|le 10^7),保证任何时刻这个图均为森林(即不会出现环)。

    题解

    https://jklover.hs-blog.cf/2019/12/27/LCT-题目选做/

    LCT 维护子树信息.

    把边拆成点,变成维护路径点权之和.

    由于 LCT 支持换根,所以只需要分别维护出一棵 Splay 中所有点到深度最小,最大的点的距离和,翻转的时候交换.

    为了能合并 Splay 左右儿子的信息,还需要维护出子树内黑点的数目,虚边的子树内黑点到对应子树根的距离和.

    当虚边被更改时将对应信息更新就可以了,时间复杂度 (O(nlog n)).

    CO int N=5e5+10;
    int ch[N][2],fa[N],rev[N];
    int col[N],si[N],siz[N]; // size of imaginary subtree
    int val[N];int64 sumv[N]; // sum of weight of edge
    int64 sumi[N],suml[N],sumr[N]; // sum of distance of imaginary subtree
    
    IN bool nroot(int x){
    	return ch[fa[x]][0]==x or ch[fa[x]][1]==x;
    }
    IN void push_up(int x){
    	siz[x]=col[x]+si[x]+siz[ch[x][0]]+siz[ch[x][1]];
    	sumv[x]=val[x]+sumv[ch[x][0]]+sumv[ch[x][1]];
    	suml[x]=sumi[x]+suml[ch[x][0]]+suml[ch[x][1]]+(col[x]+si[x]+siz[ch[x][1]])*(val[x]+sumv[ch[x][0]]);
    	sumr[x]=sumi[x]+sumr[ch[x][0]]+sumr[ch[x][1]]+(col[x]+si[x]+siz[ch[x][0]])*(val[x]+sumv[ch[x][1]]);
    }
    IN void reverse(int x){
    	swap(ch[x][0],ch[x][1]);
    	swap(suml[x],sumr[x]);
    	rev[x]^=1;
    }
    IN void push_down(int x){
    	if(rev[x]){
    		if(ch[x][0]) reverse(ch[x][0]);
    		if(ch[x][1]) reverse(ch[x][1]);
    		rev[x]=0;
    	}
    }
    IN void rotate(int x){
    	int y=fa[x],z=fa[y],l=x==ch[y][1],r=l^1;
    	if(nroot(y)) ch[z][y==ch[z][1]]=x;fa[x]=z;
    	ch[y][l]=ch[x][r],fa[ch[x][r]]=y;
    	ch[x][r]=y,fa[y]=x;
    	push_up(y);
    }
    void splay(int x){
    	vector<int> stk(1,x);
    	for(int i=x;nroot(i);) stk.push_back(i=fa[i]);
    	for(;stk.size();stk.pop_back()) push_down(stk.back());
    	for(;nroot(x);rotate(x)){
    		int y=fa[x],z=fa[y];
    		if(nroot(y)) rotate((x==ch[y][1])!=(y==ch[z][1])?x:y);
    	}
    	push_up(x);
    }
    void access(int x){
    	for(int y=0;x;y=x,x=fa[x]){
    		splay(x);
    		si[x]+=siz[ch[x][1]];
    		sumi[x]+=suml[ch[x][1]];
    		ch[x][1]=y;
    		si[x]-=siz[ch[x][1]];
    		sumi[x]-=suml[ch[x][1]];
    		push_up(x);
    	}
    }
    IN void make_root(int x){
    	access(x),splay(x),reverse(x);
    }
    int find_root(int x){
    	access(x),splay(x);
    	for(;ch[x][0];x=ch[x][0]);
    	splay(x);
    	return x;
    }
    IN void split(int x,int y){
    	make_root(x),access(y),splay(y);
    }
    IN void link(int x,int y){
    	make_root(x),access(y),splay(y);
    	fa[x]=y;
    	si[y]+=siz[x];
    	sumi[y]+=suml[x];
    	push_up(y);
    }
    IN void cut(int x,int y){
    	split(x,y);
    	fa[x]=0;
    	ch[y][0]=0;
    	push_up(y);
    }
    
    int main(){
    	int n=read<int>(),m=read<int>(),q=read<int>();
    	for(int i=1;i<=m;++i){
    		int x=read<int>(),y=read<int>(),w=read<int>();
    		val[++n]=w;
    		push_up(n);
    		link(x,n),link(y,n);
    	}
    	for(int i=1;i<=q;++i){
    		char opt[2];scanf("%s",opt);
    		if(opt[0]=='L'){
    			int x=read<int>(),y=read<int>(),w=read<int>();
    			val[++n]=w;
    			push_up(n);
    			link(x,n),link(y,n);
    		}
    		else if(opt[0]=='C'){
    			int x=read<int>(),y=read<int>();
    			split(x,y);
    			int p=ch[y][0];
    			cut(p,x),cut(p,y);
    		}
    		else if(opt[0]=='F'){
    			int x=read<int>();
    			access(x),splay(x);
    			col[x]^=1;
    			push_up(x);
    		}
    		else{
    			int x=read<int>();
    			make_root(x);
    			printf("%lld
    ",suml[x]);
    		}
    	}
    	return 0;
    }
    
  • 相关阅读:
    getWritableDatabase()与getReadableDatabase()方法
    使用drawBitmapMesh扭曲图像
    移动游戏背景
    使用Matrix控制图片和组件的变化
    使用Matrix控制图像或组件变换的步骤
    1105: 零起点学算法12——求2个日期之间的天数
    1104: 零起点学算法11——求梯形面积
    1103: 零起点学算法10——求圆柱体的表面积
    1102: 零起点学算法09——继续练习简单的输入和计算(a-b)
    1101: 零起点学算法08——简单的输入和计算(a+b)
  • 原文地址:https://www.cnblogs.com/autoint/p/13174075.html
Copyright © 2011-2022 走看看