zoukankan      html  css  js  c++  java
  • bzoj2594: [Wc2006]水管局长数据加强版

    题目大意:给定一个简单图,支持删边,每次询问两点间 最大边权值最小的路径。


    思路:题目中权值在边上,而LCT维护的全值在点上,所以要先转化,对于连接x和y的第i条路径,把边变成第i+n个点,然后把权值放到边点上,所有真正的点权值赋为0,这也是维护边权的常用方法。接着就是一个性质:每次询问两点间 最大边权值最小的路径一定是在最小生成树上。具体证明可以自行百度或YY。然后我们就可以去维护最小生成树了,但是题目是删边,没法做啊....这时我们可以倒着做,离线处理,删边就成了加边。怎么用LCT维护呢?先跑一遍kruskal,因为题目保证任意时刻图是联通的,所以一定可以跑出一棵初始的最小生成树(其实跑出一部分也没有影响...只要没有环就可以用LCT了)。然后加边,对于要连接的两点x和y,找出加边前的路径,得出路径上最大边的编号,如果新边比最大边更优,就可以把最大边替换掉,然后这题就没有然后了...

    #include<cstdio>
    #include<cstring>
    #include<iostream>
    #include<algorithm>
    #define ls c[x][0]
    #define rs c[x][1]
    using namespace std;
    const int maxm=1000010,maxq=100010,maxt=1500010;
    int n,m,Q,f[maxt],tim;char ch;
    struct edge{int u,v,w,id;bool d;}e[maxm];
    struct qu{int f,x,y,ans,id;}q[maxm];
    bool operator<(edge a,edge b){return a.u<b.u||(a.u==b.u&&a.v<b.v);}
    void read(int &x){
    	for (ch=getchar();!isdigit(ch);ch=getchar());
    	for (x=0;isdigit(ch);ch=getchar()) x=x*10+ch-'0';
    }
    
    struct LCT{
    	int fa[maxt],c[maxt][2],val[maxt],mx[maxt];bool rev[maxt];
    	int which(int x){return c[fa[x]][1]==x;}
    	bool isroot(int x){return c[fa[x]][0]!=x&&c[fa[x]][1]!=x;}	
    	void update(int x){
    		mx[x]=x;
    		if (val[mx[ls]]>val[mx[x]]) mx[x]=mx[ls];
    		if (val[mx[rs]]>val[mx[x]]) mx[x]=mx[rs];
    	}
    	void flip(int x){swap(ls,rs),rev[x]^=1;}
    	void down(int x){if (rev[x]) flip(c[x][0]),flip(c[x][1]),rev[x]^=1;}
    	void relax(int x){if (!isroot(x)) relax(fa[x]);down(x);}
    	void rotate(int x){
    		int y=fa[x],z=fa[y],nx=which(x),ny=which(y);
    		fa[c[x][!nx]]=y,c[y][nx]=c[x][!nx];
    		fa[x]=z;if (!isroot(y)) c[z][ny]=x;
    		fa[y]=x,c[x][!nx]=y;update(y);
    	}
    	void splay(int x){
    		relax(x);
    		while (!isroot(x)){
    			if (isroot(fa[x])) rotate(x);
    			else if (which(x)==which(fa[x])) rotate(fa[x]),rotate(x);
    			else rotate(x),rotate(x);
    		}
    		update(x);
    	}
    	void access(int x){for (int p=0;x;p=x,x=fa[x]) splay(x),fa[c[x][1]=p]=x,update(x);}
    	void makeroot(int x){access(x),splay(x),flip(x);}
    	void link(int a,int b){makeroot(a),fa[a]=b;}
    	void cut(int a,int b){makeroot(a),access(b),splay(b),c[b][0]=fa[a]=0;}
    	int query(int a,int b){makeroot(a),access(b),splay(b);return mx[b];}
    }T;
    
    int getfa(int x){return f[x]==x?x:f[x]=getfa(f[x]);}
    int find(int u,int v){
    	int l=1,r=m;
    	while (l<=r){
    		int mid=(l+r)>>1;
    		if (e[mid].u<u||(e[mid].u==u&&e[mid].v<v)) l=mid+1;
    		else if (e[mid].u==u&&e[mid].v==v) return mid;
    		else r=mid-1;
    	}
    }
    bool cmp(edge a,edge b){return a.w<b.w;}
    bool cmp2(edge a,edge b){return a.id<b.id;}
    
    void kruskal(){
    	int tot=0;
    	for (int i=1;i<=m;i++) 
    		if (!e[i].d){
    			int u=e[i].u,v=e[i].v;
    			if (getfa(u)!=getfa(v)){
    				f[getfa(u)]=getfa(v),T.link(u,i+n),T.link(i+n,v);
    //				printf("MST%d %d %d %d
    ",u,v,e[i].w,e[i].d);
    				if (++tot==n-1) break;
    			}
    		}
    }
    
    int main(){
    	scanf("%d%d%d",&n,&m,&Q);
    	for (int i=1;i<=n;i++) f[i]=i;
    	for (int i=1;i<=m;i++){
    		read(e[i].u),read(e[i].v),read(e[i].w);
    		if (e[i].u>e[i].v) swap(e[i].u,e[i].v);
    	}
    	sort(e+1,e+1+m,cmp);
    	for (int i=1;i<=m;i++) e[i].id=i,T.val[n+i]=e[i].w,T.mx[n+i]=n+i;
    	sort(e+1,e+1+m);
    	for (int i=1;i<=Q;i++){
    		read(q[i].f),read(q[i].x),read(q[i].y);
    		if (q[i].f==2){
    			if (q[i].x>q[i].y) swap(q[i].x,q[i].y);
    			int t=find(q[i].x,q[i].y);
    //			printf("que%d %d %d
    ",t,q[i].x,q[i].y);
    			e[t].d=1,q[i].id=e[t].id;
    		}
    	}
    	sort(e+1,e+1+m,cmp2);
    	kruskal();
    	for (int i=Q;i;i--){
    		if (q[i].f==1) q[i].ans=T.val[T.query(q[i].x,q[i].y)];
    		else{
    			int u=q[i].x,v=q[i].y,k=q[i].id,t=T.query(u,v);
    //			printf("%d %d %d %d
    ",k,e[k].v,e[k].w,T.val[t]);
    			if (e[k].w<T.val[t]){
    				T.cut(e[t-n].u,t),T.cut(e[t-n].v,t);
    				T.link(u,k+n),T.link(v,k+n);
    			}
    		}
    	}
    	for (int i=1;i<=Q;i++) if (q[i].f==1) printf("%d
    ",q[i].ans);
    	return 0;
    }

  • 相关阅读:
    如何入门深度学习
    机器学习之激活函数
    轻量化模型之SqueezeNet
    聚类算法之MeanShift
    目标检测之RefineDet
    语义分割之RefineNet
    数学基础之高斯核函数
    目标检测之人脸识别
    梯度下降算法及优化方法
    机器学习高阶训练营知识点一览
  • 原文地址:https://www.cnblogs.com/thythy/p/5493597.html
Copyright © 2011-2022 走看看