4242: 水壶

题目链接

题目大意:矩阵,有建筑物,原野,墙壁,走原野需要1单位水,建筑物可以补满水,多次询问两个建筑物间需要携带的水壶大小

题解:平面图上的最小生成树,然后就是货车运输了

Orz题解

我的收获:

#include<iostream>
#include<cstdio>
#include<cstring>
#define N 2005
#define M 200005
using namespace std;
 
int n,m,pt,cas,tot,cnt,fa[M][18],g[M][18],bin[25],anc[M],fst[M],pnt[N*N],nxt[N*N],len[N*N];
int dep[M],h[N*N][2],d[N][N],blg[N][N]; bool mp[N][N];
const int dx[4]={-1,1,0,0},dy[4]={0,0,-1,1};
int read(){
    int x=0; char ch=getchar();
    while (ch<'0' || ch>'9') ch=getchar();
    while (ch>='0' && ch<='9'){ x=x*10+ch-'0'; ch=getchar(); }
    return x;
}
struct grapg{
    int fst[N*N];
    void add(int x,int y,int z){
        pnt[++tot]=y; nxt[tot]=fst[x]; len[tot]=z; fst[x]=tot;
    }
}g1,g2;
int getanc(int x){ return (x==anc[x])?x:anc[x]=getanc(anc[x]); }
void dfs(int x){
    int p,i;
    for (i=1; bin[i]<=dep[x]; i++){
        fa[x][i]=fa[fa[x][i-1]][i-1];
        g[x][i]=max(g[x][i-1],g[fa[x][i-1]][i-1]);
    }
    for (p=g2.fst[x]; p; p=nxt[p]){
        int y=pnt[p];
        if (y!=fa[x][0]){
            fa[y][0]=x; g[y][0]=len[p];
            dep[y]=dep[x]+1; dfs(y);
        }
    }
}
int qry(int x,int y){
    if (getanc(x)!=getanc(y)) return -1;
    if (dep[x]<dep[y]) swap(x,y); int tmp=dep[x]-dep[y],i,ans=0;
    for (i=0; bin[i]<=tmp; i++)
        if (tmp&bin[i]){ ans=max(ans,g[x][i]); x=fa[x][i]; }
    for (i=17; i>=0; i--)
        if (fa[x][i]!=fa[y][i]){
            ans=max(ans,max(g[x][i],g[y][i]));
            x=fa[x][i]; y=fa[y][i];
        }
    if (x!=y) ans=max(ans,max(g[x][0],g[y][0])); return ans;
}
int main(){
    m=read(); n=read(); pt=read(); cas=read();
    int i,j; char ch=getchar();
    bin[0]=1; for (i=1; i<=18; i++) bin[i]=bin[i-1]<<1;
    for (i=1; i<=m; i++){
        while (ch!='.' && ch!='#') ch=getchar();
        for (j=1; j<=n; j++,ch=getchar())
            mp[i][j]=(ch=='.');
    }
    int head=0,tail=0,x,y,z;
    memset(d,-1,sizeof(d));
    for (i=1; i<=pt; i++){
        h[++tail][0]=x=read(); h[tail][1]=y=read();
        blg[x][y]=i; d[x][y]=0;
        anc[i]=i;
    }
    while (head<tail){
        x=h[++head][0]; y=h[head][1]; z=blg[x][y];
        for (i=0; i<4; i++){
            int u=x+dx[i],v=y+dy[i];
            if (u>0 && u<=m && v>0 && v<=n && mp[u][v])
                if (d[u][v]==-1){
                    d[u][v]=d[x][y]+1; blg[u][v]=z;
                    h[++tail][0]=u; h[tail][1]=v;
                } else if (z!=blg[u][v]) g1.add(d[u][v]+d[x][y],z,blg[u][v]);
        }
    }
    for (i=0; i<m*n; i++)
        for (j=g1.fst[i]; j; j=nxt[j]){
            x=getanc(pnt[j]); y=getanc(len[j]);
            if (x!=y){
                anc[x]=y; g2.add(pnt[j],len[j],i);
                g2.add(len[j],pnt[j],i);
            }
        }
    for (i=1; i<=pt; i++)
        if (getanc(i)==i){
            dep[i]=1; dfs(i);
        }
    while (cas--) printf("%d\n",qry(read(),read()));
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值