zoukankan      html  css  js  c++  java
  • BZOJ4242 水壶

    Time Limit: 50 Sec Memory Limit: 512 MB

    Description

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

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

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

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

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

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

    Input

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

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

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

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

    Output

    输出(Q)行,第(i)((1leq ileq Q))一个整数,表示在建筑物Si和Ti之间移动最小需要多大的水壶。

    如果无法到达,输出-1。此外,如果不需要经过原野就能到达,输出0。

    Sample Input

    5 5 4 4
    .....
    ..##.
    .#...
    ..#..
    .....
    1 1
    4 2
    3 3
    2 5
    1 2
    2 4
    1 3
    3 4
    

    Sample Output

    3
    4
    4
    2
    

    HINT

    (1leq Hleq 2000)

    (1leq W leq 2000)

    (2leq Pleq 2 imes10^5)

    (1leq Qleq 2 imes 10^5)

    (1leq A_ileq H(1leq ileq P))

    (1leq B_ileq W(1leq ileq P))

    ((A_i,B_i)≠(A_j,B_j)(1leq i<jleq P))

    (1leq Si<Tileq P(1leq ileq Q))

    Source

    JOI 2013~2014 春季training合宿 竞技2 By PoPoQQQ

    Solution

    嗯这道题目第一眼看上去就是货车运输的清奇的画风啊。

    问题是如何建边。

    你肯定不能把一共(W imes H)个点放进图里面来建边吧。这样跑最小生成树。。。不太了解。Update:这个是我一开始很傻的想法,现在突然发先这样好像就是错的,根本做不了。

    我们只把(P)个点放过来建边。显然两个点之间的边就应该是在地图中的最短距离吧。但是我们需要把(P^2)组最短距离缩减成一棵树。

    所以我们对一共(P)个建筑物同时开始BFS,然后对于每个空地,第一个BFS到它的建筑物就记录一下,后面的所有BFS到之的建筑物都和第一个BFS到的连边,边权为距离即可。然后我们得到一个图,跑最小生成树就可以了。因为这个边权不超过(W*H),所有可以用vector或者链表按边权存一下边,省去了跑排序的(log)

    为什么不用把所有点之间全都连边就可以保证正确性呢?其实这个结论很显然啊。因为第一个BFS到这个点的一定是离他最近的,顺边去最近的补水不是常规操作吗。。。反正也没要求走最短路。

    #include<cstdio>
    #include<algorithm>
    #include<cmath>
    #include<cstring>
    #include<vector>
    using namespace std;
    #define lowbit(x) ((x)&(-(x)))
    #define REP(i,a,n) for(register int i=(a);i<=(n);++i)
    #define PER(i,a,n) for(register int i=(a);i>=(n);--i)
    #define FEC(i,x) for(register int i=head[x];i;i=g[i].ne)
    #define dbg(...) fprintf(stderr,__VA_ARGS__)
    template<typename A>inline void read(A&a){a=0;char c=0;int f=1;while(c<'0'||c>'9')(c=getchar())=='-'?f=-1:0;while(c>='0'&&c<='9')a=(a<<3)+(a<<1)+c-'0',c=getchar();f==-1?a=-a:0;}
    char buf[30];template<typename A>inline void write(A a){if(a<0)putchar('-'),a=-a;int top=0;if(!a)buf[top=1]='0';while(a)buf[++top]=a%10+'0',a/=10;while(top)putchar(buf[top--]);}
    typedef long long ll;typedef unsigned long long ull;
    template<typename A,typename B>inline bool SMAX(A&x,const B&y){return x<y?x=y,1:0;}
    template<typename A,typename B>inline bool SMIN(A&x,const B&y){return y<x?x=y,1:0;}
    
    const int H=2000+7,N=2e5+7,LOG=19,fx[]={0,0,1,0,-1},fy[]={0,1,0,-1,0};
    int w,h,n,Q,x,y,del[H][H],vis[H][H],f[N][LOG],s[N][LOG],dep[N],mxd;char a[H][H];
    struct Edge{int to,ne,w;}g[N<<1];int head[N],tot;
    inline void Addedge(int x,int y,int z){g[++tot].to=y,g[tot].w=z;g[tot].ne=head[x];head[x]=tot;}
    struct Graph{int x,y,z;};vector<Graph>G[H*H];
    
    struct Node{int x,y,fr,s;}q[H*H];int hd,tl;
    inline void BFS(){
    	while(hd<tl){
    		Node t=q[++hd];
    		for(register int i=1;i<=4;++i){
    			int px=t.x+fx[i],py=t.y+fy[i];
    			if(px<1||px>h||py<1||py>w||a[px][py])continue;
    			if(vis[px][py]>0&&vis[px][py]!=t.fr){G[del[px][py]+t.s].push_back(Graph{vis[px][py],t.fr}),SMAX(mxd,del[px][py]+t.s);continue;}else if(vis[px][py])continue;
    			vis[px][py]=t.fr;del[px][py]=t.s+1;q[++tl]=Node{px,py,t.fr,t.s+1};
    		}
    	}
    }
    
    int fa[N];
    inline int Find(int x){return fa[x]==x?x:fa[x]=Find(fa[x]);}
    inline void Union(int x,int y){x=Find(x),y=Find(y),fa[y]=x;}
    inline void Kruskal(){
    	for(register int i=1;i<=n;++i)fa[i]=i;
    	for(register int i=0,cnt=0;i<=mxd;++i){//错误笔记:从0开始循环,允许有的边权为0 
    		int len=G[i].size();
    		for(register int j=0;j<len;++j){
    			int x=Find(G[i][j].x),y=Find(G[i][j].y);if(x==y)continue;
    			Union(x,y);Addedge(G[i][j].x,G[i][j].y,i),Addedge(G[i][j].y,G[i][j].x,i);++cnt;if(cnt==n-1)continue;
    		}
    	}
    }
    
    inline void DFS(int x,int fa=0){
    	f[x][0]=fa;dep[x]=dep[fa]+1;for(register int i=1;i<LOG;++i)f[x][i]=f[f[x][i-1]][i-1],s[x][i]=max(s[x][i-1],s[f[x][i-1]][i-1]);
    	for(register int i=head[x];i;i=g[i].ne)if(g[i].to!=fa)s[g[i].to][0]=g[i].w,DFS(g[i].to,x);
    }
    inline int LCA(int x,int y){
    	if(dep[x]<dep[y])x^=y^=x^=y;int ans=0;
    	for(register int i=LOG-1;i>=0;--i)if(dep[f[x][i]]>=dep[y])SMAX(ans,s[x][i]),x=f[x][i];
    	if(x==y)return ans;
    	for(register int i=LOG-1;i>=0;--i)if(f[x][i]!=f[y][i])SMAX(ans,s[x][i]),SMAX(ans,s[y][i]),x=f[x][i],y=f[y][i];
    	return max(ans,max(s[x][0],s[y][0]));
    }
    
    int main(){
    #ifndef ONLINE_JUDGE
    	freopen("BZOJ4242.in","r",stdin);freopen("BZOJ4242.out","w",stdout);
    #endif
    	read(h),read(w),read(n),read(Q);
    	for(register int i=1;i<=h;++i){
    		scanf("%s",a[i]+1);
    		for(register int j=1;j<=w;++j)a[i][j]=a[i][j]=='#';
    	}
    	for(register int i=1;i<=n;++i){read(x),read(y);vis[x][y]=i;q[++tl]=Node{x,y,i,0};}
    	BFS();Kruskal();for(register int i=1;i<=n;++i)if(!dep[i])DFS(i);
    	for(register int i=1;i<=Q;++i){
    		read(x),read(y);
    		write(Find(x)==Find(y)?LCA(x,y):-1),putchar('
    ');
    	}
    }
    
  • 相关阅读:
    bzoj 4066: 简单题 K-D树
    SAS获取最后一条观测到指定宏
    sas 获取字符串长度实例
    tomcat Error:NB:JAVA_HOME should point to a JDK not a JRE 解决方法
    ODBC数据源管理器-》系统DSN-》没有....Microsoft Access Driver(*mdb,*,accdb)
    SAS DATA ENCODING 解决odbc乱码问题
    sas 日期比较代码备忘
    sas transpose 代码备忘
    svn 红叉叉图标解决方法
    echart line 初始化隐藏legend
  • 原文地址:https://www.cnblogs.com/hankeke/p/9848401.html
Copyright © 2011-2022 走看看