Codeforces 1262E Arson In Berland Forest(二维前缀和+二维差分+二分)

 题意是需要求最大的扩散时间,最后输出的是一开始的火源点,那么我们比较容易想到的是二分找最大值,但是我们在这满足这样的点的时候可以发现,在当前扩散时间k下,以这个点为中心的(2k+1)2的正方形块内必须全部都是'X'才行,那么要访问这样的块内的'X'个数显然需要使用二维前缀和维护一下就可以O(1)求出个数,那么这部分问题我们解决,接下来就是二分的如何Check,那么既然我们之前找到了这样满足当期扩散时间的点后,我们只需要直接将这块矩形内部的点全部打标记,显然我们可以得知,如果当前扩散时间是满足要求的,那么所有的'X'最后都会被打上标记,那么我们可以利用这一性质,对满足这样的矩形进行二维差分,最后O(n*m)把标记推掉,在check一遍所有被打伤标记的点是不是等于等于一开始'X'的个数,若等于,那么我们可以将区间移至右边,否则移至左边。

最后记得不要用cin,cout,T的死去活来.....

 1 //      ——By DD_BOND 
 2  
 3 #include<bits/stdc++.h>
 4  
 5 using namespace std;
 6  
 7 typedef long long ll;
 8 
 9 const int MAXN=1e6+10;
10  
11 inline ll sqr(ll x){ return x*x; }
12  
13 char s[MAXN];
14  
15 int main(void)
16 {
17     int n,m;    scanf("%d%d",&n,&m);
18     vector<vector<int> >ok (n+2,vector<int>(m+2));
19     vector<vector<int> >sum(n+2,vector<int>(m+2));
20     vector<vector<int> >tmp(n+2,vector<int>(m+2));
21     for(int i=1;i<=n;i++){
22         scanf("%s",s+1);
23         for(int j=1;j<=m;j++)    if(s[j]=='X')   sum[i][j]=1;
24     }
25     for(int i=1;i<=n;i++)
26         for(int j=1;j<=m;j++)
27             sum[i][j]+=sum[i-1][j]+sum[i][j-1]-sum[i-1][j-1];
28     int l=0,r=(min(n,m)-1)/2,res=0;
29     while(l<=r){
30         int mid=(l+r)>>1;
31         for(int i=1;i<=n;i++)
32             for(int j=1;j<=m;j++)
33                 tmp[i][j]=0;
34         for(int i=mid+1;i<=n-mid;i++)
35             for(int j=mid+1;j<=m-mid;j++)
36                 if(sum[i+mid][j+mid]-sum[i-mid-1][j+mid]-sum[i+mid][j-mid-1]+sum[i-mid-1][j-mid-1]==sqr(2*mid+1)){
37                     tmp[i-mid][j-mid]+=1;
38                     tmp[i-mid][j+mid+1]+=-1;
39                     tmp[i+mid+1][j-mid]+=-1;
40                     tmp[i+mid+1][j+mid+1]+=1;
41                 }
42         int f=0;
43         for(int i=1;i<=n;i++)
44             for(int j=1;j<=m;j++)
45                 if(tmp[i][j]+=tmp[i-1][j]+tmp[i][j-1]-tmp[i-1][j-1])
46                     f++;
47         if(f==sum[n][m])   l=mid+1,res=mid;
48         else    r=mid-1;
49     }
50     printf("%d\n",res);
51     for(int i=res+1;i<=n-res;i++)
52         for(int j=res+1;j<=m-res;j++)
53             if(sum[i+res][j+res]-sum[i-res-1][j+res]-sum[i+res][j-res-1]+sum[i-res-1][j-res-1]==sqr(2*res+1))
54                 ok[i][j]=1;
55     for(int i=1;i<=n;i++){
56         for(int j=1;j<=m;j++)   putchar((ok[i][j]?'X':'.'));
57         puts("");
58     }
59     return 0;
60 }
posted @ 2019-11-26 12:05  DD_BOND  阅读(350)  评论(0编辑  收藏  举报