[51NOD1743][JZOJ4899]雪之国度

来源:互联网 发布:网站备案域名怎么买 编辑:程序博客网 时间:2024/05/02 03:28

题目大意

给定n个点,m条边的无向图。每个点有点权wi,一条边(x,y)的边权定义为|wxwy|
q询问,每次询问两个点(x,y),如果xy之间存在至少两条互不相交(没有重复边)的路径,那么输出这两条路径上边权的最大值(如果有多对路径,选择最小的),否则输出1

3n105,3m5×105,1q105


题目分析

考虑一种最暴力的做法,按边权从小到大插入边,动态维护边双连通分量。连通分量内的答案可以瞎处理。然而这样很难维护。
怎么办呢?用最小生成树来维护一个联通性,这样然后在树上可以更方便的处理边双内路径的最大权值。我们可能会加入某些边使得它有环,那么环内权值就要变成加入这条边的权值(加入边肯定更大)。但是修改过一次的边我们就不能再修改了,因为显然它达到了条件且不会更优。因此我们使用并查集来将所有修改过的点并在一起,这样修改时就可以暴力沿着并查集父亲修改了。
处理询问的话,倍增查询路径最大值即可。
时间复杂度O(nlog2n)


代码实现

#include <algorithm>#include <iostream>#include <cstdio>#include <cctype>#include <cmath>using namespace std;int read(){    int x=0,f=1;    char ch=getchar();    while (!isdigit(ch)) f=ch=='-'?-1:f,ch=getchar();    while (isdigit(ch)) x=x*10+ch-'0',ch=getchar();    return x*f;}int buf[30];void write(int x){    if (x<0) x=-x,putchar('-');    for (;x;x/=10) buf[++buf[0]]=x%10;    if (!buf[0]) buf[++buf[0]]=0;    for (;buf[0];) putchar('0'+buf[buf[0]--]);}const int N=100050;const int M=500050;const int E=N<<1;const int LGN=17;struct edge{    int x,y,l;}e[M];bool operator<(edge a,edge b){return a.l<b.l;}int fa[N],deep[N],last[N],w[N];int f[N][LGN],anc[N][LGN];int tov[E],nxt[E],len[E];int n,m,q,tot,lgn,ans;bool chosen[M];int getfather(int son){return fa[son]==son?son:fa[son]=getfather(fa[son]);}void insert(int x,int y,int z){tov[++tot]=y,len[tot]=z,nxt[tot]=last[x],last[x]=tot;}void dfs(int x){    for (int i=last[x],y;i;i=nxt[i])        if ((y=tov[i])!=anc[x][0])            anc[y][0]=x,deep[y]=deep[x]+1,f[y][0]=len[i],dfs(y);}void pre(){    lgn=trunc(log(n)/log(2));    for (int j=1;j<=lgn;j++)        for (int i=1;i<=n;i++)            anc[i][j]=anc[anc[i][j-1]][j-1],f[i][j]=max(f[i][j-1],f[anc[i][j-1]][j-1]);}int adjust(int x,int d){    for (int i=lgn;i>=0;i--)        if (deep[anc[x][i]]>=d) ans=max(ans,f[x][i]),x=anc[x][i];    return x;}void getans(int x,int y){    ans=0;    if (deep[x]>deep[y]) swap(x,y);    y=adjust(y,deep[x]);    if (x==y) return;    for (int i=lgn;i>=0;i--)        if (anc[x][i]!=anc[y][i]) ans=max(ans,max(f[x][i],f[y][i])),x=anc[x][i],y=anc[y][i];    ans=max(ans,max(f[x][0],f[y][0])),x=anc[x][0],y=anc[y][0];}int main(){    freopen("city.in","r",stdin),freopen("city.out","w",stdout);    n=read(),m=read(),q=read();    for (int i=1;i<=n;i++) w[i]=read(),fa[i]=i;    for (int i=1;i<=m;i++) e[i].x=read(),e[i].y=read(),e[i].l=abs(w[e[i].x]-w[e[i].y]);    sort(e+1,e+1+m);    for (int i=1,x,y,fx,fy;i<=m;i++)    {        fx=getfather(x=e[i].x),fy=getfather(y=e[i].y);        if (fx!=fy)        {            chosen[i]=1;            fa[fy]=fx;            insert(x,y,e[i].l),insert(y,x,e[i].l);        }    }    anc[1][0]=0,deep[1]=1,dfs(1);    for (int i=1;i<=n;i++) fa[i]=i;    for (int i=1,x,y;i<=m;i++)        if (!chosen[i])            for (x=getfather(e[i].x),y=getfather(e[i].y);x!=y;x=getfather(x))            {                if (deep[x]<deep[y]) swap(x,y);                f[x][0]=max(e[i].l,f[x][0]);                fa[x]=anc[x][0];            }    pre();    for (int x,y;q--;)    {        x=read(),y=read();        if (getfather(x)!=getfather(y)||x==y) printf("infinitely\n");        else getans(x,y),write(ans),putchar('\n');    }    fclose(stdin),fclose(stdout);    return 0;}
1 0
原创粉丝点击