您的位置:首页 > 其它

jzoj100048 【NOIP2017提高A组模拟7.14】紧急撤离 (网格图,分治,bitSet)

2017-07-14 20:19 441 查看

题意

给出一个n*m <=500*500的网格图,有一些点有障碍。从一个点只能向下,向右走,询问q<=6∗105:(a,b)是否能到达(c,d)。

分析

询问这么多,如果不是并查集的话一定是预处理了。

考虑直接做,对于每一个询问要nm的时间来暴力。

优化?

枚举一个中间点,然后向两边寻找。

如何配对询问?

将询问用边集数组之类的打到点上。再用O(q)时间询问。

这样我们就切掉了这题 才怪咧,一个点的时间是O(n2),整张图是多少?

等等

不一定经过定点

但是在那一列两侧的一定经过那一列!

考虑分治

将从列mid切开,如果不经过中间的就左右两个区间分治搞。

经过中间的如何计算?

暴力还是n3的,考虑dp。发现dp也可以求出一个点(x,y)能到中间点的哪些点。

O(n3)

但如果dp使用bitset压位优化,时间就可以除掉一个常数32。

T(m)=2T(m2)+n2m/32

这样分下去可以分log m次,不难看出每一层都是n2m/32,所以最后时间复杂度就是O(n2m logm /32+q),也就是O(n3+q)。 从这里可以发现如果不用bitset那么时间就会多一个log,会T得飞起。

询问需要保证只会被访问一次,所以插入边集数组时有排序姿势。

CODE

#include <iostream>
#include <cstdio>
#include <bitset>
#include <cstring>
#include <algorithm>
#define N 510
using namespace std;
bitset<N> bs

;
int n,m,q,ans[600001],tot;
int next[600001],head

;
bool map

;
struct req{
int lx,ly,rx,ry,to;
} a[600001],re[600001];
bool cmp(req x,req y) {return x.ry<y.ry;}
void link(int x,int y,const req &r) {
re[++tot]=r; next[tot]=head[x][y]; head[x][y]=tot;
}
void init() {
cin>>n>>m;
char c;
for (int i=1; i<=n; i++) {
scanf("\n");
for (int j=1; j<=m; j++) {
c=getchar(); map[i][j]=1-(c-'0');
}
}
cin>>q;
for (int i=1; i<=q; i++) scanf("%d %d %d %d",&a[i].lx,&a[i].ly,&a[i].rx,&a[i].ry),a[i].to=i;
sort(a+1,a+1+q,cmp);
for (int i=q; i; i--) link(a[i].lx,a[i].ly,a[i]);
}
void divide(int l,int r) {
if (l>r) return; int mid=l+r>>1;
divide(l,mid-1);
divide(mid+1,r);
for (int i=1; i<=n; i++) for (int j=l; j<=r; j++) bs[i][j].reset();
for (int i=1; i<=n; i++) if (map[i][mid]) bs[i][mid].set(i);
for (int j=mid; j>=l; j--) for (int i=n; i; i--)
if (map[i][j]) bs[i][j]|=bs[i+1][j] | bs[i][j+1];
for (int i=1; i<=n; i++) {
bs[i][mid].reset();
if (map[i][mid]) bs[i][mid].set(i);
}
for (int j=mid; j<=r; j++) for (int i=1; i<=n; i++)
if (map[i][j]) {
bs[i][j]|=bs[i-1][j];
if (j!=mid) bs[i][j]|=bs[i][j-1];
}
for (int i=1; i<=n; i++) for (int j=l; j<=mid; j++) {
for (int z=head[i][j]; z; z=next[z]) {
if (re[z].ry>r) break;
head[i][j]=next[z];
if (re[z].ry==re[z].ly) ans[re[z].to]=bs[re[z].rx][re[z].ry][re[z].lx];
else if (re[z].ry==mid) ans[re[z].to]=bs[i][j][re[z].rx];
else if (j==mid) ans[re[z].to]=bs[re[z].rx][re[z].ry][re[z].lx];
else if ((bs[i][j] & bs[re[z].rx][re[z].ry]).any()) ans[re[z].to]=1;
}
}
}
int main() {
freopen("3.in","r",stdin);
freopen("3.out","w",stdout);
init();
divide(1,m);
for (int i=1; i<=q; i++) if (ans[i]) printf("Safe\n"); else printf("Dangerous\n");
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: