zoukankan      html  css  js  c++  java
  • P4172 [WC2006]水管局长

    https://www.luogu.com.cn/problem/P4172
    https://darkbzoj.tk/problem/2594
    bzoj 那个是加强版

    lct 维护动态最小瓶颈树

    题意:给一个图,每次询问两个点之间路径的最大值的最小值,或断开一个边,始终保证图连通

    用 lct 维护,发现断边不怎么好做,所以离线下来倒序处理,常规套路
    就是先跑一个最小瓶颈生成树,然后每次加边,如果加的这个边的边权大于它两个端点间原来路径的最大值,就不管他,否则,把两端点原来路径上权值最大的边断开,把新边加进去

    在实现操作前,要先清楚 lct 如何维护边的信息,其实可以为每一个边新建一个虚拟节点,权值为边权,其它的真实节点点权都是零
    然后每次让两个点相连,就是让它们分别与连的这个边对应的虚拟节点相连就行了

    然后两种操作只要都先 split 出来然后处理就行了
    为了方便知道哪个路径上的边是边权最大的,lct 节点中的 max 保存的实际上是最大边权的边的编号

    由于 (n) 比较小(普通版),所以一开始建 lct 之前的操作怎么乱搞都行,不过我这样写就过不了加强版了,那个加强版又是卡时又是卡空间的懒得写了

    #include<cstdio>
    #include<algorithm>
    #include<iostream>
    #include<cmath>
    #include<map>
    #include<iomanip>
    #include<cstring>
    #define reg register
    #define EN std::puts("")
    #define LL long long
    inline int read(){
    	register int x=0;register int y=1;
    	register char c=std::getchar();
    	while(c<'0'||c>'9'){if(c=='-') y=0;c=std::getchar();}
    	while(c>='0'&&c<='9'){x=x*10+(c^48);c=std::getchar();}
    	return y?x:-x;
    }
    #define N 1005
    #define M 100005
    int n,m,q;
    int allu[M],allv[M],allw[M];
    int id[N][N],map[N][N];
    struct data{
    	int u,v,w,id;
    }edge[M];
    int tot;
    int K[M],U[M],V[M],ANS[M];
    struct tr{
    	tr *son[2],*fa;
    	int tag,max,val;
    }*null,*pos[N+M],dizhi[N+M];
    //1 - n 实际点
    //n+1 - n+m 代表边
    #define pushup(tree) (tree->max=max(max(tree->son[0]->max,tree->son[1]->max),tree->val))
    #define ident(tree,fa) (fa->son[1]==tree)
    #define notroot(tree) (tree->fa->son[0]==tree||tree->fa->son[1]==tree)
    inline int max(int x,int y){return allw[x]>allw[y]?x:y;}
    inline void connect(tr *tree,tr *fa,int k){tree->fa=fa;fa->son[k]=tree;}
    inline void pushdown(tr *tree){
    	if(!tree->tag) return;
    	tree->tag=0;
    	tree->son[0]->tag^=1;tree->son[1]->tag^=1;
    	std::swap(tree->son[0],tree->son[1]);
    }
    inline void rotate(tr *tree){
    	reg tr *fa=tree->fa,*faa=fa->fa;
    	pushdown(fa);pushdown(tree);
    	int k=ident(tree,fa);
    	connect(tree->son[k^1],fa,k);
    	tree->fa=faa;
    	if(notroot(fa)) faa->son[ident(fa,faa)]=tree;
    	connect(fa,tree,k^1);
    	pushup(fa);pushup(tree);
    }
    inline void splay(reg tr *tree){
    	reg tr *fa,*faa;
    	while(notroot(tree)){
    		fa=tree->fa;faa=fa->fa;
    		if(notroot(fa)) rotate(ident(tree,fa)^ident(fa,faa)?tree:fa);
    		rotate(tree);
    	}
    }
    inline void access(tr *x){
    	for(reg tr *lastx=null;x!=null;lastx=x,x=x->fa){
    		pushdown(x);splay(x);
    		x->son[1]=lastx;pushup(x);
    	}
    }
    inline void makeroot(tr *tree){
    	access(tree);splay(tree);
    	tree->tag^=1;
    }
    inline void split(tr *x,tr *y){
    	makeroot(x);
    	access(y);splay(y);
    }
    inline void link(tr *x,tr *y){
    	makeroot(x);x->fa=y;
    }
    inline void cut(tr *x,tr *y){
    	split(x,y);
    	x->fa=y->son[0]=null;
    }
    inline void init(){
    	null=&dizhi[0];
    	for(reg int i=1;i<=n;i++){
    		pos[i]=&dizhi[i];
    		dizhi[i].son[0]=dizhi[i].son[1]=dizhi[i].fa=null;
    	}
    	for(reg int i=n+1;i<=n+m;i++){
    		pos[i]=&dizhi[i];
    		dizhi[i].son[0]=dizhi[i].son[1]=dizhi[i].fa=null;
    		dizhi[i].max=dizhi[i].val=i-n;
    	}
    }
    inline int cmp(data a,data b){return a.w<b.w;}
    int fa[N];
    inline int find(int x){return x==fa[x]?x:fa[x]=find(fa[x]);}
    inline void build(){
    	for(reg int i=1;i<=n;i++)for(reg int j=1;j<i;j++)if(map[i][j])
    		edge[++tot].u=i,edge[tot].v=j,edge[tot].w=map[i][j],edge[tot].id=id[i][j];
    	std::sort(edge+1,edge+1+tot,cmp);
    	for(reg int i=1;i<=n;i++) fa[i]=i;
    	for(reg int i=1,cnt=1;cnt<n;i++)if(find(edge[i].u)!=find(edge[i].v)){
    		fa[fa[edge[i].u]]=fa[edge[i].v];
    		link(pos[edge[i].u],pos[n+edge[i].id]);link(pos[edge[i].v],pos[n+edge[i].id]);
    		cnt++;
    	}
    }
    int main(){
    	n=read();m=read();q=read();
    	for(reg int u,v,i=1;i<=m;i++){
    		allu[i]=u=read();allv[i]=v=read();
    		map[u][v]=map[v][u]=allw[i]=read();
    		id[u][v]=id[v][u]=i;
    	}
    	for(reg int i=1;i<=q;i++){
    		K[i]=read();U[i]=read();V[i]=read();
    		if(K[i]==2) map[U[i]][V[i]]=map[V[i]][U[i]]=0;
    	}
    	init();build();
    	for(reg int u,v,i=q;i;i--){
    		if(K[i]==1){
    			split(pos[U[i]],pos[V[i]]);
    			ANS[i]=allw[pos[V[i]]->max];
    		}
    		else{//保证了图连通,不用再判连通性
    			u=U[i];v=V[i];
    			split(pos[u],pos[v]);
    			int maxpos=pos[v]->max;
    			if(allw[maxpos]>allw[id[u][v]]){
    				cut(pos[allu[maxpos]],pos[maxpos+n]);cut(pos[allv[maxpos]],pos[maxpos+n]);
    				link(pos[u],pos[id[u][v]+n]);link(pos[v],pos[id[u][v]+n]);
    			}
    		}
    	}
    	for(reg int i=1;i<=q;i++)if(K[i]==1) printf("%d
    ",ANS[i]);
    	return 0;
    }
    
  • 相关阅读:
    jQuery.fly插件实现添加购物车抛物线效果
    jQuery 实现前端模糊匹配与首字母搜索
    Java生成微信二维码及logo二维码
    Map 与 JavaBean 的相互装换
    从零写Java Web框架——请求的处理DispatcherServlet
    从零写Java Web框架——实现Ioc依赖注入
    记一次校招面试
    使用DbUtils对JDBC封装实现面向实体查询
    HTTP Status 500 PWC6188 jsp/jstl/core cannot be resolved in either web.xml or the jar files deployed with this application
    【插件】百度编译器ueditor插入视频的时候。在预览的窗口提示 “输入的视频地址有误,请检查后再试!
  • 原文地址:https://www.cnblogs.com/suxxsfe/p/13494068.html
Copyright © 2011-2022 走看看