• 【51nod1743】雪之国度(最小生成树+倍增)


    点此看题面

    大致题意: 给你一张无向连通图,其中每条边的边权为这条边连接的两点的权值之差。每次询问两点之间是否存在两条不重复的路径,若存在则输出这两条路径上最大值的最小值。

    大致思路

    这题显然就是要让你维护边双

    我们可以先对原图求一遍最小生成树,然后再将其余非树边(按权值从小到大先排一次序)一条一条地加到图中。

    对于这条边连接的两个点,我们需要对它们在树上路径进行修改。

    要注意的是,对于已经修改过的,我们就不能对它进行再一次修改,因为边已经排过序,新加上的边肯定没有原来加上的边更优。

    至于维护,可以采用并查集

    如果要查询,直接采用倍增法在树上乱跳求答案即可。

    代码

    #include<bits/stdc++.h>
    #define ten(x) (((x)<<3)+((x)<<1))
    #define N 100000
    #define M 500000
    #define LogN 20
    #define INF 1000000000
    #define add(x,y,z) (e[++ee].nxt=lnk[x],e[lnk[x]=ee].to=y,e[ee].val=z)
    #define max(x,y) ((x)>(y)?(x):(y))
    #define min(x,y) ((x)<(y)?(x):(y))
    #define abs(x) ((x)<0?-(x):(x)) 
    using namespace std;
    int n,m,ee=0,val[N+5],lnk[N+5];
    struct edge
    {
    	int from,to,nxt,val,vis;
    	inline friend bool operator < (edge x,edge y) {return x.val<y.val;}//按边权从小到大排序
    }s[M+5],e[(N<<1)+5];
    class FIO
    {
    	private:
    		#define Fsize 100000
    		#define tc() (A==B&&(B=(A=Fin)+fread(Fin,1,Fsize,stdin),A==B)?EOF:*A++)
    		#define pc(ch) (FoutSize<Fsize?Fout[FoutSize++]=ch:(fwrite(Fout,1,Fsize,stdout),Fout[(FoutSize=0)++]=ch))
    		int Top,FoutSize;char ch,*A,*B,Fin[Fsize],Fout[Fsize],Stack[Fsize];
    	public:
    		inline void read(int &x) {x=0;while(!isdigit(ch=tc()));while(x=ten(x)+(ch&15),isdigit(ch=tc()));}
    		inline void write(int x) {if(!x) return (void)(pc('0'));while(x) Stack[++Top]=x%10+48,x/=10;while(Top) pc(Stack[Top--]);}
    		inline void write_char(char x) {pc(x);}
    		inline void write_string(string x) {for(register int i=0,len=x.length();i<len;++i) pc(x[i]);}
    		inline void clear() {fwrite(Fout,1,FoutSize,stdout);}
    }F;
    class UnionFindSet//并查集
    {
    	public:
    		int fa[N+5];
    		inline void Clear() {for(register int i=1;i<=N;++i) fa[i]=i;}
    		UnionFindSet() {Clear();}
    		inline int getfa(int x) {return fa[x]^x?fa[x]=getfa(fa[x]):x;}
    		inline void Union(int x,int y) {if((x=getfa(x))^(y=getfa(y))) fa[y]=x;}
    }U;
    class Class_MulSolver//倍增
    {
    	public:
    		int Depth[N+5],fa[N+5][LogN+5],Max[N+5][LogN+5];
    	private:
    		inline void dfs(int x,int lst)//DFS遍历预处理
    		{
    			for(register int i=lnk[x];i;i=e[i].nxt)
    				if(e[i].to^lst) Depth[e[i].to]=Depth[fa[e[i].to][0]=x]+1,Max[e[i].to][0]=e[i].val,dfs(e[i].to,x);
    		}
    	public:
    		inline void DfsInit() {dfs(1,0);}
    		inline void MulInit() {for(register int i,j=1;j<=LogN;++j) for(i=1;i<=n;++i) fa[i][j]=fa[fa[i][j-1]][j-1],Max[i][j]=max(Max[i][j-1],Max[fa[i][j-1]][j-1]);}//预处理倍增数组
    		inline int get_max(int x,int y)//求树上路径最大值
    		{
    			if(Depth[x]<Depth[y]) swap(x,y);
    			register int i,res=0;
    			for(i=0;Depth[x]^Depth[y];++i) if((Depth[x]^Depth[y])&(1<<i)) res=max(res,Max[x][i]),x=fa[x][i];
    			if(!(x^y)) return res;
    			for(i=0;fa[x][i]^fa[y][i];++i);
    			for(--i;i>=0;--i) if(fa[x][i]^fa[y][i]) res=max(res,max(Max[x][i],Max[y][i])),x=fa[x][i],y=fa[y][i];
    			return max(res,max(Max[x][0],Max[y][0]));
    		}
    }MulSolver;
    int main()
    {
    	register int i,Q,x,y;
    	for(F.read(n),F.read(m),F.read(Q),i=1;i<=n;++i) F.read(val[i]);
    	for(i=1;i<=m;++i) F.read(s[i].from),F.read(s[i].to),s[i].val=abs(val[s[i].from]-val[s[i].to]);//存边
    	for(sort(s+1,s+m+1),i=1;i<=m;++i) if(U.getfa(s[i].from)^U.getfa(s[i].to)) U.Union(s[i].from,s[i].to),s[i].vis=1,add(s[i].from,s[i].to,s[i].val),add(s[i].to,s[i].from,s[i].val);//建一棵最小生成树
    	for(U.Clear(),MulSolver.DfsInit(),i=1;i<=m;++i)//将非树边一条一条加到树上 
    	{
    		if(s[i].vis) continue;//如果是树边,跳过
    		for(x=U.getfa(s[i].from),y=U.getfa(s[i].to);x^y;x=U.getfa(x))//如果遇到已修改过的,则结束更新过程
    		{
    			if(MulSolver.Depth[x]<MulSolver.Depth[y]) swap(x,y);//如果x比y深度小,交换
    			MulSolver.Max[x][0]=s[i].val,U.fa[x]=MulSolver.fa[x][0];//更新信息
    		}
    	}
    	for(MulSolver.MulInit();Q;--Q) F.read(x),F.read(y),(U.getfa(x)^U.getfa(y)?F.write_string("infinitely
    "):(F.write(MulSolver.get_max(x,y)),F.write_char('
    ')));//用倍增法求解
    	return F.clear(),0;
    }
    
  • 相关阅读:
    最新美丽说网购平台模板
    红色的原油投资金融专题模板
    简单响应式Bootstrap框架中文官网页面模板
    蓝色简约的工业大学学校网站静态模板
    红色经典招生校园网站全套
    白色简洁的瑞班克个人博客网站
    仿360影视网站模板html
    红色的企业新闻门户网站模板
    橙色的汽车蚂蚁企业门户网站模板
    使用ExtJS做一个用户的增删改查
  • 原文地址:https://www.cnblogs.com/chenxiaoran666/p/51nod1743.html
Copyright © 2020-2023  润新知