水壶-[Kruskal重构树] [解题报告]

水壶

本来从不写针对某题的题解,但因为自己实在是太蠢了,这道题也神TM的恶心,于是就写篇博客纪念一下


H水壶
时间限制 : 50000 MS 空间限制 : 565536 KB 评测说明 : 2s,512m
问题描述

\(JOI\)君所居住的IOI市以一年四季都十分炎热著称。

\(IOI\)市是一个被分成\(H*W\)块区域的长方形,每个区域都是建筑物、原野、墙壁之一。建筑物的区域有\(P\)个,编号为\(1...P\)

$ JOI$君只能进入建筑物与原野,而且每次只能走到相邻的区域中,且不能移动到市外。

\(JOI\)君因为各种各样的事情,必须在各个建筑物之间往返。虽然建筑物中的冷气设备非常好,但原野上的日光十分强烈,因此在原野上每走过一个区域都需要\(1\)单位的水。此外,原野上没有诸如自动售货机、饮水处之类的东西,因此\(IOI\)市的市民一般都携带水壶出行。大小为\(x\)的水壶最多可以装\(x\)单位的水,建筑物里有自来水可以将水壶装满。

由于携带大水壶是一件很困难的事情,因此\(JOI\)君决定携带尽量小的水壶移动。因此,为了随时能在建筑物之间移动,请你帮他写一个程序来计算最少需要多大的水壶。

现在给出\(IOI\)市的地图和\(Q\)个询问,第i个询问\((1<=i<=Q)\)为“在建筑物\(S_i\)\(T_i\)之间移动,最小需要多大的水壶?”,请你对于每个询问输出对应的答案。

输入格式

第一行四个空格分隔的整数\(H,W,P,Q\),表示\(IOI\)市被分成了纵\(H*W\)块区域,有\(P\)个建筑物,\(Q\)次询问。

接下来\(H\)行,第\(i\)\((1<=i<=H)\)有一个长度为\(W\)的字符串,每个字符都是’.’或’#’之一,\(’.’\)表示这个位置是建筑物或原野,’#’表示这个位置是墙壁。

接下来\(P\)行描述\(IOI\)市每个建筑物的位置,第\(i\)\((1<=i<=P)\)有两个空格分隔的整数\(Ai\)\(Bi\),表示第i个建筑物的位置在第\(A_i\)行第\(B_i\)列。保证这个位置在地图中是’.’

接下来\(Q\)行,第\(i\)\((1<=i<=Q)\)有两个空格分隔的整数\(S_i\)\(T_i\),表示第\(i\)个询问为“在建筑物\(Si\)\(Ti\)之间移动,最小需要多大的水壶?”

输出格式

输出\(Q\)行,第\(i\)\((1<=i<=Q)\)一个整数,表示在建筑物\(S_i\)\(T_i\)之间移动最小需要多大的水壶。 如果无法到达,输出\(-1\)。此外,如果不需要经过原野就能到达,输出\(0\)

样例输入

5 5 4 4
.....

..##.

.#...

..#..

.....

1 1

4 2

3 3

2 5

1 2

2 4

1 3

3 4

样例输出

3

4

4

2

提示

\(1<=H<=2000\)

\(1<=W<=2000\)

\(2<=P<=2*10^5\)

\(1<=Q<=2*10^5\)

\(1<=A_i<=H(1<=i<=P)\)

\(1<=B_i<=W(1<=i<=P)\)

\((A_i,B_i)≠(A_j,B_j)(1<=i<j<=P)\)

\(1<=S_i<T_i<=P(1<=i<=Q)\)


题解

很显然这道题的询问类似于\(NOIP2015\)运输计划(不知道是不是这年的题啊),我们可以轻松愉快的使用\(Kruskal\)重构树或者很棒很棒的直接倍增记录;

但是这个方格图就很恶心,我们需要自己建一个仅有我们所需建筑的点和链接他们的边的图出来,这可咋整?

这就是这道题较为恶心的地方,我们可以对每一块染色,每当我们到达一个已被其他颜色染色的合法区域,把这条边就可以加入我们的存边数组,不知道开多大,就用\(Vector\)来存储;

但其实这并不是恶心我的地方\(,,,\),恶心的是\(LCA\)居然写错,\(WA,MLE\)到天上了简直惨死,下次再在写\(Kruskal\)重构树求\(LCA\)时把\(log_[tot]\)开成\(log_[n]\)就原地自爆,更别提写LCA写成Del=dep[x]-dep[x];


\(code:\)
#include<cstdio>
#include<algorithm>
#include<ctype.h> 
#include<vector>
#include<queue>
#include<cstring>
#define lowbit(x) (x&-x)
#define ll long long
#define ld double
#include<map>
#include<stdlib.h>
#include<ctime>
#define mod 19260817
using namespace std;

char buf[1<<20],*p1,*p2;
inline char gc()
{
//    return getchar();
    return p1==p2&&(p2=(p1=buf)+fread(buf,1,1<<20,stdin))==p1?0:*p1++;
}

template<typename T>
inline void read(T &x)
{
    char tt;
    bool flag=0;
    while(!isdigit(tt=gc())&&tt!='-');
    tt=='-'?(flag=1,x=0):(x=tt-'0');
    while(isdigit(tt=gc())) x=x*10+tt-'0';
    if(flag) x=-x;
}

const int maxn=200002;
struct node{
    int x,y,len;
    inline node(int a=0,int b=0,int c=0)
    {x=a,y=b;len=c;}
    inline bool operator<(node a)const
    {return len>a.len;}
};

int n,m,p,que,tot;
int w[maxn<<1],fa[maxn<<1][20],dd[maxn<<1],dep[maxn<<1];
int log_[maxn<<1];
int book[2002][2002],dis[2002][2002];
int dx[4]={0,0,1,-1},dy[4]={1,-1,0,0};
char G[2002][2002];
vector<int>g[maxn<<1];
vector<node>a;
queue<node>q;

int getfa(int x){
return x==dd[x]?x:dd[x]=getfa(dd[x]);
}

void bfs()
{
    for(int i=1;i<=p;i++)
    {
        int x,y;
        read(x),read(y);
        q.push(node(x,y));
        book[x][y]=i;
    }
    while(!q.empty())
    {
        int id,x,y;
        x=q.front().x,y=q.front().y;
		id=book[x][y];q.pop();
        for(int i=0;i<4;i++)
        {
            int tx=x+dx[i],ty=y+dy[i];
            if(tx<=0||tx>n||ty<=0||ty>m||G[tx][ty]=='#'||book[tx][ty]==id) continue;
            if(book[tx][ty])
            a.push_back(node(id,book[tx][ty],dis[x][y]+dis[tx][ty]));
            else
            {
            	q.push(node(tx,ty));
            	dis[tx][ty]=dis[x][y]+1;
            	book[tx][ty]=id;
			}
        }
    }
}

void dfs(int x,int pre)
{
	dep[x]=dep[pre]+1,fa[x][0]=pre;
	for(int i=1;i<=log_[tot];i++)
	if(fa[x][i-1]) fa[x][i]=fa[fa[x][i-1]][i-1];
	else break;
	
	for(int i=g[x].size()-1;i>=0;i--)
	{
		int p=g[x][i];
		if(p==pre) continue;
		dfs(p,x);
	}
}

int query(int x,int y)
{
	int fx=getfa(x),fy=getfa(y);
    if(fx!=fy) return -1;
    if(dep[x]<dep[y]) swap(x,y);
    if(x==y) return 0;
    int del=dep[x]-dep[y];
    for(int i=log_[tot];i>=0;i--)
    if(del>>i&1) x=fa[x][i];
    if(x==y) return w[x];
    for(int i=log_[n];i>=0;i--)
    if(fa[x][i]!=fa[y][i]) x=fa[x][i],y=fa[y][i];
    return w[fa[x][0]];
}

int main()
{
    read(n),read(m),read(p),read(que);
    for(int i=1;i<=n;i++,gc())
    for(int j=1;j<=m;j++)
    G[i][j]=gc();tot=p;
    bfs();
	sort(a.begin(),a.end());log_[0]=-1;
    for(int i=1;i<=p<<1;i++) dd[i]=i,log_[i]=log_[i>>1]+1;
	for(int i=a.size()-1;i>=0;i--)
	{
		int fx=getfa(a[i].x),fy=getfa(a[i].y),len=a[i].len;;
		if(fx==fy) continue;
		dd[fx]=dd[fy]=++tot;
		g[tot].push_back(fx);
		g[tot].push_back(fy);
		w[tot]=len;
	}
	for(int i=tot;i>=1;i--) if(!dep[i]) dfs(i,0);
	while(que--)
	{
		int x,y;
		read(x),read(y);
		printf("%d\n",query(x,y));
	}
}

找个时间填\(Kruskal\)重构树的坑\(ORZ,ORZ\)

posted @ 2018-10-21 00:09  Katoumegumi  阅读(270)  评论(0编辑  收藏  举报
返回顶部