【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\n"):(F.write(MulSolver.get_max(x,y)),F.write_char('\n')));//用倍增法求解
    return F.clear(),0;
}

原文地址:https://www.cnblogs.com/chenxiaoran666/p/51nod1743.html

时间: 2024-10-25 05:54:02

【51nod1743】雪之国度(最小生成树+倍增)的相关文章

[51nod1743]雪之国度

雪之国度有N座城市,依次编号为1到N,又有M条道路连接了其中的城市,每一条道路都连接了不同的2个城市,任何两座不同的城市之间可能不止一条道路. 雪之女王赋予了每一座城市不同的能量,其中第i座城市被赋予的能量为Wi. 如果城市u和v之间有一条道路,那么只要此刻雪之女王的能量不小于|Wu-Wv|,这条道路就是安全的. 如果城市u和v之间存在两条没有重复道路的安全路径(其中每一段道路都是安全的),则认为这两座城市之间有着良好的贸易关系. 最近,雪之女王因为情感问题,她的能量产生巨大的波动.为了维持雪之

【bzoj4242】水壶 BFS+最小生成树+倍增LCA

题目描述 JOI君所居住的IOI市以一年四季都十分炎热著称. IOI市是一个被分成纵H*横W块区域的长方形,每个区域都是建筑物.原野.墙壁之一.建筑物的区域有P个,编号为1...P. JOI君只能进入建筑物与原野,而且每次只能走到相邻的区域中,且不能移动到市外. JOI君因为各种各样的事情,必须在各个建筑物之间往返.虽然建筑物中的冷气设备非常好,但原野上的日光十分强烈,因此在原野上每走过一个区域都需要1单位的水.此外,原野上没有诸如自动售货机.饮水处之类的东西,因此IOI市的市民一般都携带水壶出

codevs 1519 过路费 最小生成树+倍增

/*codevs 1519 过路费 最小生成树+倍增*/ #include<iostream> #include<cstdio> #include<cstring> #include<algorithm> #define maxn 100010 #define inf 0x3f3f3f3 using namespace std; int n,m,q,num,head[maxn],fa[maxn][25],mx[maxn][25],c[maxn],father

HDU 4081 Qin Shi Huang&#39;s National Road System 最小生成树+倍增求LCA

原题链接:http://acm.hdu.edu.cn/showproblem.php?pid=4081 Qin Shi Huang's National Road System Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)Total Submission(s): 5428    Accepted Submission(s): 1902 Problem Description

【CodeForces】827 D. Best Edge Weight 最小生成树+倍增LCA+并查集

[题意]给定n个点m条边的带边权无向连通图,对每条边求最大边权,满足其他边权不变的前提下图的任意最小生成树都经过它.n,m<=2*10^5,1<=wi<=10^9. [算法]最小生成树+倍增LCA+并查集 [题解]首先求出图的一个最小生成树,则所有边分成树边和非树边. 对于非树边(u,v),假设u和v在最小生成树上的路径的最大边权Max,那么一定满足w(u,v)<=Max /////////////////////////////////////// 原文地址:https://ww

训练指南 UVA - 11354(最小生成树 + 倍增LCA)

layout: post title: 训练指南 UVA - 11354(最小生成树 + 倍增LCA) author: "luowentaoaa" catalog: true mathjax: true tags: - 最小生成树 - LCA - 图论 - 训练指南 Bond UVA - 11354 题意 给你一张无向图,然后有若干组询问,让你输出a->b的最小瓶颈路 题解 先求出最小生成树,然后对这个最小生成树做LCA. #include<bits/stdc++.h>

bzoj3732 -- 最小生成树+倍增

显然使A到B的最长边最小的路径一定在最小生成树上,否则一定可以使生成树更小. 求出原图的最小生成树,然后用倍增求路径上最大值就可以了. 代码: 1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 #include<queue> 5 using namespace std; 6 #define N 15010 7 #define S 15 8 struct Edge{ 9 int f,t,

MST(最小生成树+倍增)

题目描述: 给定一个n个点m条边的连通图,保证没有自环和重边.对于每条边求出,在其他边权值不变的情况下,它能取的最大权值,使得这条边在连通图的所有最小生成树上.假如最大权值为无限大,则输出-1. 题解: 先求出图的一棵最小生成树: 对于不在树上的边(x,y), 它的权值只要小于树上x到y路径中一条边就可以代替这条边. 对于在树上的边(x,y),可以先预处理出所有两端在x到y路径上的不在树上的边的最小值.它的权值一定要小于最小值. 路径max和min都可以用倍增求. 时间复杂度O(nlogn) #

【XSY2485】MST(最小生成树+倍增lca+并查集)

题面 Description 给定一个\(n\)个点\(m\)条边的连通图,保证没有自环和重边.对于每条边求出,在其他边权值不变的情况下,它能取的最大权值,使得这条边在连通图的所有最小生成树上.假如最大权值为无限大,则输出\(-1\). Input 第一行两个整数\(n\),\(m\),表示\(n\)个点\(m\)条边 接下来\(m\)行,每行\(3\)个整数\(x\),\(y\),\(z\),表示节点\(x\)和节点\(y\)之间有一条长\(z\)的边. Output 输出一行\(m\)个整数