• bzoj4242 水壶


    https://www.lydsy.com/JudgeOnline/problem.php?id=4242

    显然答案应该为建筑物构成的最小生成树中,两点间的最大路径;那么只要得到这棵最小生成树就可以用倍增在O(
    QlogN)的时间内得到答案了。因此关键是求最小生成树。注意到是平面图,因此考虑用bfs求最小生成树。直接以
    每个建筑为原点拓展显然不行,那么我们可以把每个建筑都加入队列一起拓展,那么对于一个点,一定会被其中的
    一个建筑第一次拓展到,则令这个点为该建筑的“势力范围”。那么对于两个建筑“势力范围”边界上接触的点,
    显然这两个建筑之间的边只能有边界上的点得到。因此就用这些点连边即可。显然这样得到是最小生成树。然后用
    倍增求lca的方法得到答案即可。当然也可以用Krutal重构树来做。

    #include<queue>
    #include<cstdio>
    #include<algorithm>
    #define N 2005
    #define P 200010
    #define M 10000010
    using namespace std;
    char ch,B[1<<15],*S=B,*T=B;
    #define getc() (S==T&&(T=(S=B)+fread(B,1,1<<15,stdin),S==T)?0:*S++)
    inline int read()
    {
    int x=0,f=1;char ch=getc();
    while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getc();}
    while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getc();}
    return x*f;
    }
    int head[P],tot,n,all,W,H,m;
    int dx[]={0,0,1,-1};
    int dy[]={1,-1,0,0};
    bool map[N][N];
    int belong[N][N],dis[N][N];
    struct edge
    {
    int next,to,v;
    }e[P<<1];
    struct Edge{int x,y,z;}E[M];
    bool operator<(Edge x,Edge y)
    {
    return x.z<y.z;
    }
    void add(int u,int v,int w)
    {
    e[++tot]=(edge){head[u],v,w};
    head[u]=tot;
    e[++tot]=(edge){head[v],u,w};
    head[v]=tot;
    }
    struct node{int x,y;};
    queue<node>q;
    void bfs()
    {
    while(!q.empty())
    {
    int x=q.front().x;
    int y=q.front().y;
    q.pop();
    for(int k=0;k<4;k++)
    {
    int nx=x+dx[k],ny=y+dy[k];
    if(nx<1||nx>H||ny<1||ny>W)
    continue;
    if(map[nx][ny])
    continue;
    if(!belong[nx][ny])//如果这个点没有扩展过的话
    {
    belong[nx][ny]=belong[x][y];
    dis[nx][ny]=dis[x][y]+1;
    q.push((node){nx,ny});
    }
    else //如果已扩展过则两点可以连边
    if(belong[nx][ny]<belong[x][y])
    {
    E[++all]=(Edge){belong[x][y],belong[nx][ny],dis[x][y]+dis[nx][ny]-2};
    }
    }
    }
    }
    int fa[P][19],Log[P],deep[P],f[P],d[P][19];
    int find(int x)
    {
    return f[x]==x?x:f[x]=find(f[x]);
    }
    void dfs(int x)
    {
    deep[x]=deep[fa[x][0]]+1;
    for(int i=1;deep[x]>(1<<i);i++)
    fa[x][i]=fa[fa[x][i-1]][i-1],
    d[x][i]=max(d[x][i-1],d[fa[x][i-1]][i-1]);
    for(int i=head[x];i;i=e[i].next)
    if(e[i].to!=fa[x][0])
    {
    fa[e[i].to][0]=x;
    d[e[i].to][0]=e[i].v;
    dfs(e[i].to);
    }
    }
    int getdis(int x,int y)
    {
    if(find(x)!=find(y))
    return -1;
    if(deep[x]<deep[y])
    swap(x,y);
    int t=deep[x]-deep[y],ans=0;
    for(int i=Log[t];~i;i--)
    if(t&(1<<i))
    ans=max(ans,d[x][i]),x=fa[x][i];
    if(x==y)return ans;
    for(int i=Log[deep[x]];~i;i--)
    if(fa[x][i]!=fa[y][i])
    ans=max(ans,max(d[x][i],d[y][i])),
    x=fa[x][i],y=fa[y][i];
    return max(ans,max(d[x][0],d[y][0]));
    }
    int main()
    {
    H=read();W=read();n=read();m=read();
    for(int i=2;i<=n;i++)Log[i]=Log[i>>1]+1;
    char s;
    for(int i=1;i<=H;i++)
    for(int j=1;j<=W;j++)
    {
    while(s=getc(),s!='.'&&s!='#');
    map[i][j]=(s=='#');
    }
    int x,y;
    for(int i=1;i<=n;i++)
    {
    x=read();
    y=read();
    belong[x][y]=i;
    dis[x][y]=1;
    q.push((node){x,y});
    }
    bfs();
    sort(E+1,E+all+1);
    //将边权从小到大排序,因为对于两个建筑物可以用不同的边连起来,自然我们要用最小值。
    for(int i=1;i<=n;i++) //并查集操作
    f[i]=i;
    for(int i=1;i<=all;i++)
    {
    int fx=find(E[i].x),fy=find(E[i].y);
    if(fx!=fy)
    {
    f[fy]=fx;
    add(E[i].x,E[i].y,E[i].z); //x到y连一条边长为z
    }
    }
    for(int i=1;i<=n;i++)
    if(!deep[i])
    dfs(i);
    while(m--)
    printf("%d\n",getdis(read(),read()));
    }

  • 相关阅读:
    UDP:用户数据报协议(User Datagram Protocol)
    线程池的使用
    SQL Server表和模式空间使用情况http://www.51myit.com/thread2466911.html
    bytetobmp and bmptobyte(Image)
    c# TCP例子转载
    POJ 4047Garden
    NYOJ 102 次方求模
    Sum
    POJ 1094 Sorting It All Out(经典拓扑,唯一排序)
    POJ 2387 Til the Cows Come Home(Dijkstra)
  • 原文地址:https://www.cnblogs.com/cutemush/p/11735085.html
Copyright © 2020-2023  润新知