zoukankan      html  css  js  c++  java
  • BZOJ 2594: [Wc2006]水管局长数据加强版(lct)

    传送门

    解题思路

      一道(lct)维护动态最小生成树。刚开始写了一遍疯狂(Re),冷静了一下重新写了一遍终于过了。首先题目中要求两点之间最大值的最小值,其实就是维护一个最小生成树,每次询问最大值。要将删边转化成加边操作,就是倒着处理,这里用(set)(map)就比较方便。然后还要把边权转化成点权,具体来说就是假如(x,y)直接有一条权值为(z)的边,那么就新开一个节点,令这个点的权值为(z),然后连接(x)与这个节点,(y)与这个节点。(lct)里维护一下最大值的节点的编号。每当假如一条边时要判断一下这条路径的最大值是否大于新加入的边,大于的话就先(cut)掉最大值,然后再(link)

    代码

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<cstdlib>
    #include<algorithm>
    #include<map>
    #include<set>
    
    using namespace std;
    const int MAXN = 100005;
    const int MAXM = 1000005;
    
    inline int rd(){
    	int x=0,f=1;char ch=getchar();
    	while(!isdigit(ch)) {f=ch=='-'?0:1;ch=getchar();}
    	while(isdigit(ch))  {x=(x<<1)+(x<<3)+ch-'0';ch=getchar();}
    	return f?x:-x;
    } 
    
    int n,m,q,num,fa[MAXN+MAXM],ch[MAXN+MAXM][2],Max[MAXN+MAXM];
    int F[MAXN],val[MAXN+MAXM],tot,xx[MAXN+MAXM],yy[MAXN+MAXM];
    int cnt,ans[MAXN];
    bool tag[MAXN+MAXM];
    map<pair<int,int>,int > mp;
    set<pair<int,int> > S;
    
    struct Edge{
    	int x,y,z,id;
    	friend bool operator<(const Edge A,const Edge B){
    		return A.z<B.z;
    	}
    }edge[MAXM];
    
    struct Query{
    	int x,y,type,id;
    }ask[MAXN];
    
    int Find(int x){
    	if(x==F[x]) return x;
    	return F[x]=Find(F[x]);
    }
    
    inline bool check(int x){
    	return (x==ch[fa[x]][1]);
    }
    
    inline bool isroot(int x){
    	return (x!=ch[fa[x]][0] && x!=ch[fa[x]][1]);
    }
    
    inline void pushup(int x){
    	Max[x]=x;
    	if(val[Max[ch[x][0]]]>val[Max[x]]) Max[x]=Max[ch[x][0]];
    	if(val[Max[ch[x][1]]]>val[Max[x]]) Max[x]=Max[ch[x][1]];
    }
    
    inline void pushdown(int x){
    	if(tag[x]){
    		tag[x]=0;swap(ch[x][0],ch[x][1]);
    		if(ch[x][0]) tag[ch[x][0]]^=1;
    		if(ch[x][1]) tag[ch[x][1]]^=1;
    	}
    }
    
    void pd(int x){
    	if(!isroot(x)) pd(fa[x]);pushdown(x);
    }
    
    inline void rotate(int x){
    	int y=fa[x],z=fa[y];bool chk=check(x);
    	if(!isroot(y)) ch[z][check(y)]=x;
    	ch[y][chk]=ch[x][chk^1];fa[ch[x][chk^1]]=y;
    	ch[x][chk^1]=y;fa[y]=x;fa[x]=z;pushup(y);pushup(x);
    }
    
    inline void splay(int x){
    	pd(x);
    	for(;!isroot(x);rotate(x))
    		if(!isroot(fa[x])) rotate(check(fa[x])==check(x)?fa[x]:x);
    }
    
    inline void access(int x){
    	for(int y=0;x;y=x,x=fa[x]){
    		splay(x);ch[x][1]=y;pushup(x);
    	}
    }
    
    inline void makeroot(int x){
    	access(x);splay(x);tag[x]^=1;
    }
    
    inline void link(int x,int y){
    	makeroot(x);fa[x]=y;pushup(y);
    }
    
    inline void cut(int x,int y){
    	makeroot(x);access(y);splay(y);
    	ch[y][0]=fa[x]=0;pushup(y);
    }
    
    inline void split(int x,int y){
    	makeroot(x);access(y);splay(x);
    }
    
    int main(){
    	n=rd(),m=rd(),q=rd();int x,y,z;num=n;
    	for(int i=1;i<=n;i++) F[i]=i;
    	for(int i=1;i<=m;i++) {
    		x=rd(),y=rd(),z=rd();if(x>y) swap(x,y);
    		edge[i].x=x,edge[i].y=y,edge[i].z=z;
    		mp[make_pair(x,y)]=z;
    	}
    	for(int i=1;i<=q;i++){
    		z=rd(),x=rd(),y=rd();if(x>y) swap(x,y);
    		if(z==2) S.insert(make_pair(x,y));
    		ask[i].type=z;ask[i].x=x;ask[i].y=y;
    	}
    	sort(edge+1,edge+1+m);int u,v;
    	for(int i=1;i<=m;i++){
    		x=edge[i].x,y=edge[i].y;
    		if(S.find(make_pair(x,y))!=S.end()) continue;
    		u=Find(x);v=Find(y);if(u==v) continue;
    		F[u]=v;val[++num]=edge[i].z;link(x,num);link(num,y);
    		xx[num]=x;yy[num]=y;tot++;if(tot==n-1) break;
    	}int x1,x2;
    	for(int i=q;i;i--){
    		x=ask[i].x;y=ask[i].y;
    		if(ask[i].type==1) {split(x,y);ans[++cnt]=val[Max[x]];}
    		else{
    			val[++num]=mp[make_pair(x,y)];
    			split(x,y);if(val[Max[x]]<=val[num]) continue;
    			x1=xx[Max[x]];x2=Max[x]; //!!!注意这里要把值拿出来,否则第一个$cut$的时候有可能改变这里的值。
    			cut(xx[Max[x]],Max[x]);cut(x2,x1);
    			link(x,num);link(num,y);xx[num]=x;yy[num]=y;
    		}
    	}
    	for(int i=cnt;i;i--) printf("%d
    ",ans[i]);
    	return 0;
    }
    
  • 相关阅读:
    隔行变色&&鼠标移入变色
    滚动之固定顶部
    页面滚动之回到顶部
    定时器之秒表
    定时器之小僵尸的移动
    tomcat+spring+https
    域名相关
    【软件创意】智能Goals (android)
    【神一样的作业】二维数组连续的二维子数组的和(元素可以连续)
    【软件工程】敏捷开发方法的总结
  • 原文地址:https://www.cnblogs.com/sdfzsyq/p/10043110.html
Copyright © 2011-2022 走看看