bzoj 4242: 水壶

题意

JOI君所居住的IOI市以一年四季都十分炎热著称。
IOI市是一个被分成纵H*横W块区域的长方形,每个区域都是建筑物、原野、墙壁之一。建筑物的区域有P个,编号为1…P。
JOI君只能进入建筑物与原野,而且每次只能走到相邻的区域中,且不能移动到市外。
JOI君因为各种各样的事情,必须在各个建筑物之间往返。虽然建筑物中的冷气设备非常好,但原野上的日光十分强烈,因此在原野上每走过一个区域都需要1单位的水。此外,原野上没有诸如自动售货机、饮水处之类的东西,因此IOI市的市民一般都携带水壶出行。大小为x的水壶最多可以装x单位的水,建筑物里有自来水可以将水壶装满。
由于携带大水壶是一件很困难的事情,因此JOI君决定携带尽量小的水壶移动。因此,为了随时能在建筑物之间移动,请你帮他写一个程序来计算最少需要多大的水壶。
现在给出IOI市的地图和Q个询问,第i个询问(1<=i<=Q)为“在建筑物Si和Ti之间移动,最小需要多大的水壶?”,请你对于每个询问输出对应的答案。

题解

很久以前模拟赛出的一个题。。当时不会做啊。。
过了几个月才来更正
很容易想到最小生成树,然后在树上面倍增
问题就是怎么求最小生成树
直接做 n2 n 2 的话显然不现实
我们可以考虑广搜,因为边权都是1
所以如果两个点在同一个格子遇到了,基本上就是最优值
并且肯定后来的后来的一个不用从这个格子走下去了
因为肯定如果通过这个格子相连,肯定是连先来的比较优
但是遇到是不是一定就是最优值呢?
于是就只有 n2 n 2 条边了,可以通过
也不是。。
因为扩展中的状态还是有1的相差,所以我们把边无脑丢进去,跑一次最小生成树就可以了

最后显然是一个树上倍增
但是和求LCA的姿势有一点点不一样,最后跳的一步是两条边都要看看,SB的我只看了一条。。WA了几发。。

CODE:

#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<algorithm>
#include<iostream>
#include<queue>
using namespace std;
const int N=2005;
const int P=200005;
int h,w,p,Q;
int mp[N][N];//这个是什么 
int X[4]={-1,0,0,1};
int Y[4]={0,-1,1,0};
struct qq{int x,y,z;}E[N*N];int Num;
struct qt{int x,y,z,last;}e[P*2];int num,last[P];
queue<pair<int,int> > q;
int belong[N][N];
int d[N][N];
void Init (int x,int y,int z)
{
    Num++;
    E[Num].x=x;E[Num].y=y;E[Num].z=z;
}
void init (int x,int y,int z)
{
    num++;
    e[num].x=x;e[num].y=y;e[num].z=z;
    e[num].last=last[x];
    last[x]=num;
}
bool cmp (qq x,qq y){return x.z<y.z;}
int f[P];
int find (int x){return f[x]==x?f[x]:f[x]=find(f[x]);}
void bt ()
{
    sort(E+1,E+1+Num,cmp);
    for (int u=1;u<=p;u++) f[u]=u;
    for (int u=1;u<=Num;u++)
    {
        int x=find(E[u].x),y=find(E[u].y);
        if (x==y) continue;
        init(x,y,E[u].z);
        init(y,x,E[u].z);
        f[x]=y;
    }
    /*for (int u=1;u<=num;u++) 
    {
        printf("%d %d %d\n",e[u].x,e[u].y,e[u].z);
        system("pause");
    }*/
}
int fa[P][21];
int g[P][21];
int dep[P];
void dfs (int x,int ff,int gg)
{
    //printf("OZY:%d %d\n",x,gg);
    dep[x]=dep[ff]+1;fa[x][0]=ff;g[x][0]=gg;
    for (int u=1;u<=20;u++) 
    {
        fa[x][u]=fa[fa[x][u-1]][u-1];
        g[x][u]=max(g[x][u-1],g[fa[x][u-1]][u-1]);
    }
    for (int u=last[x];u!=-1;u=e[u].last)
    {
        int y=e[u].y;
        if (y==ff) continue;
        dfs(y,x,e[u].z);
    }
}
int get (int x,int y)
{
    if (dep[x]>dep[y]) swap(x,y);
    int ans=0;
    for (int u=20;u>=0;u--)
        if (dep[fa[y][u]]>=dep[x])
        {
            ans=max(ans,g[y][u]);
            y=fa[y][u];
        }
    if (x==y) return ans;
    for (int u=20;u>=0;u--)
        if (fa[x][u]!=fa[y][u])
        {
            ans=max(ans,g[x][u]);
            ans=max(ans,g[y][u]);
            x=fa[x][u];y=fa[y][u];
        }
//  printf("%d %d\n",x,g[x][0]);
    return max(ans,max(g[x][0],g[y][0]));
}
int main()
{
/*  freopen("data1.in","r",stdin);
    freopen("OZY.out","w",stdout);*/
    num=0;memset(last,-1,sizeof(last));
    scanf("%d%d%d%d",&h,&w,&p,&Q);
    char ch=getchar();
    for (int u=1;u<=h;u++)
    {
        while (ch!='.'&&ch!='#') ch=getchar();
        for (int i=1;i<=w;i++)
        {
            mp[u][i]=(ch=='.');
            ch=getchar();
        }
    }
    memset(d,-1,sizeof(d));
    for (int u=1;u<=p;u++)
    {
        int x,y;
        scanf("%d%d",&x,&y);//这个东西是OK的 
        q.push(make_pair(x,y));
        belong[x][y]=u;d[x][y]=0;
    }
    while (!q.empty())
    {
        int x=q.front().first,y=q.front().second;q.pop();
        /*printf("%d %d\n",x,y);
        system("pause");*/
        for (int u=0;u<4;u++)
        {
            int xx=x+X[u],yy=y+Y[u];
            if (xx>=1&&xx<=h&&yy>=1&&yy<=w&&mp[xx][yy]==1)
            {
                if (d[xx][yy]==-1)
                {
                    d[xx][yy]=d[x][y]+1;
                    belong[xx][yy]=belong[x][y];
                    q.push(make_pair(xx,yy));
                }
                else
                {
                    if (belong[xx][yy]!=belong[x][y])
                        Init(belong[xx][yy],belong[x][y],d[xx][yy]+d[x][y]);
                }
            }
        }

    }
    bt();
    for (int u=1;u<=p;u++)
        if (fa[u][0]==0)
        {
        //  printf("%d\n",u);
            dfs(u,0,0);
        }
    while (Q--)
    {
        int x,y;
        scanf("%d%d",&x,&y);
        if (find(x)!=find(y)) printf("-1\n");
        else printf("%d\n",get(x,y));
    }
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值