• Luogu 2173 [ZJOI2012]网络


    传送门
    这是一道函数很杂的LCT题。(有点类似Qtree6,Qtree7。但略难。)

    思路:

    c那么小,直接建c棵树。

    处理方式:

    1. 更改每棵树上该点的值。
    2. 最难点。先找到边的颜色(一颗一颗找),如果找不到,输出“No such edge.”。
      如果边的颜色与更改后的相同,输出“Success.”。
      cnt[x][y]xycnt[x][y]表示与x相连的颜色为y的边的边数,就可以方便地判“Error 1.”
      设变化后的颜色为w,若在对应的树上两个点已经联通,则输出“Error 2.“
      最后,删边建边,输出“Success."就行。
    3. splay节点加一个mx参数即可。

    代码:

    #include<cstdio>
    #include<cctype>
    #include<cstring>
    #include<algorithm>
    #define g g()
    #define lc tr[x].son[0]
    #define rc tr[x].son[1]
    using namespace std;
    const int N=1e4+10,inf=0x7fffffff,size=1<<25;
    int d[N];struct node{int f,son[2],mx;bool v;};
    int n,m,c,k;char cnt[N][12];
    struct Link_Cut_Tree{
    	node tr[N];
    	void update(int x){tr[x].mx=max(d[x],max(tr[lc].mx,tr[rc].mx));}
    	void fz(int x){//翻转 
    		tr[x].v=0;swap(lc,rc);
    		tr[lc].v^=1;tr[rc].v^=1;
    	}
    	bool rt(int x){return tr[tr[x].f].son[0]!=x&&tr[tr[x].f].son[1]!=x;}//是否为根 
    	void dfs(int x){//递归维护 
    		if(!rt(x))dfs(tr[x].f);
    		if(tr[x].v)fz(x);
    	}
    	void rotate(int x,int w){//旋转 
    		int f=tr[x].f,ff=tr[f].f,r,R;
    		r=tr[x].son[w];R=f;tr[R].son[1-w]=r;if(r)tr[r].f=R;
    		r=x;R=ff;if(tr[R].son[0]==f)tr[R].son[0]=r;else if(tr[R].son[1]==f)tr[R].son[1]=r; tr[r].f=R;
    		r=f;R=x;tr[R].son[w]=r;tr[r].f=R;update(f);update(x);
    	}
    	void splay(int x){
    		dfs(x);
    		while(!rt(x)){
    			int f=tr[x].f;
    			if(rt(f))rotate(x,tr[f].son[0]==x);
    			else{
    				int ff=tr[f].f,a=(tr[f].son[0]==x),b=(tr[ff].son[0]==f);
    				if(a^b)rotate(x,a),rotate(x,b);
    				else rotate(f,a),rotate(x,a);
    			}
    		}
    	}
    	void access(int x){for(int y=0;x;x=tr[y=x].f)splay(x),rc=y,update(x);}
    	void makeroot(int x){access(x);splay(x);tr[x].v^=1;}
    	int find_root(int x){access(x);splay(x);while(lc)x=lc;return x;}
    	void split(int x,int y){makeroot(y);access(x);splay(x);}
    	bool connect(int x,int y){split(x,y);return lc==y&&(!tr[y].son[1]);}//x,y是否有边连接 
    	bool unicom(int x,int y){split(x,y);while(lc)x=lc;return x==y;}//判联通 
    	void link(int x,int y){makeroot(x);tr[x].f=y;access(x);}
    	void cut(int x,int y){split(x,y);lc=0;tr[y].f=0;update(x);}
    	int query(int x,int y){return unicom(x,y)?tr[x].mx:-1;}
    }lct[12];
    //0
    void change(int x,int w){
    	d[x]=w;
    	for(int i=0;i<c;i++)lct[i].access(x),lct[i].splay(x),lct[i].update(x);
    }
    //1
    void color(int x,int y,int w){
    	int z=-1;
    	for(int i=0;i<c;i++)if(lct[i].connect(x,y)){z=i;break;}//有了splay,用什么map查边(常数那么大) 
    	if(z==w){puts("Success.");return;}//坑点 
    	if(z<0){puts("No such edge.");return;}
    	if((cnt[x][w]>=2||cnt[y][w]>=2)){puts("Error 1.");return;}//
    	if(lct[w].unicom(x,y)){puts("Error 2.");return;}
    	lct[z].cut(x,y); cnt[x][z]--;cnt[y][z]--;
    	lct[w].link(x,y);cnt[x][w]++;cnt[y][w]++;
    	puts("Success.");
    }
    //2
    int ask(int w,int x,int y){return lct[w].query(x,y);}
    
    char buf[size],*p1=buf,*p2=buf;
    char g{return p1==p2&&(p2=(p1=buf)+fread(buf,1,size,stdin),p1==p2)?EOF:*p1++;}
    void qr(int &x){
    	char c=g;bool v=x=0;
    	while(!(isdigit(c)||c=='-'))c=g;
    	if(c=='-')v=1,c=g;
    	while(isdigit(c))x=x*10+c-'0',c=g;
    	if(v)x=-x;
    }
    void write(int x){
    	if(x/10)write(x/10);
    	putchar(x%10+'0');
    }
    void pri(int x){
    	if(x<0)putchar('-'),x=-x;
    	write(x);puts("");
    }
    
    int main(){
    	qr(n);qr(m);qr(c);qr(k);
    	for(int j=0;j<c;j++)lct[j].tr[0].mx=-inf;//初始化 
    	for(int i=1;i<=n;i++){
    		qr(d[i]);
    		for(int j=0;j<c;j++)lct[j].tr[i].mx=d[i];//初始化 
    	}
    	int op,x,y,w;
    	while(m--)qr(x),qr(y),qr(w),lct[w].link(x,y),cnt[x][w]++,cnt[y][w]++;
    	while(k--){
    		qr(op);
    		switch(op){
    			case 0:qr(x);qr(y);change(x,y);break;
    			case 1:qr(x);qr(y);qr(w);color(x,y,w);break;
    			case 2:qr(w);qr(x);qr(y);pri(ask(w,x,y));break;
    		}
    	}
    	return 0;
    }
    
  • 相关阅读:
    vue table 中 列 加上 下划线和click 方法
    vue 比较好的学习文章
    Hive 以及mysql 中如何做except 数据操作
    oracle 日期维表 原始版本 带注解
    RMI 实现的rpc 远程过程调用 Java
    剑指offer20:定义栈的数据结构,请在该类型中实现一个能够得到栈中所含最小元素的min函数(时间复杂度应为O(1))。
    剑指offer19:按照从外向里以顺时针的顺序依次打印出每一个数字,4 X 4矩阵: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 则依次打印出数字1,2,3,4,8,12,16,15,14,13,9,5,6,7,11,10.
    模拟通讯录
    剑指offer17:输入两棵二叉树A,B,判断B是不是A的子结构。(ps:我们约定空树不是任意一个树的子结构)
    剑指offer16:输入两个单调递增的链表,合成后的链表满足单调不减规则。
  • 原文地址:https://www.cnblogs.com/zsyzlzy/p/12373892.html
Copyright © 2020-2023  润新知