博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Codeforces 480.E Parking Lot
阅读量:5127 次
发布时间:2019-06-13

本文共 5889 字,大约阅读时间需要 19 分钟。

E. Parking Lot
time limit per test
3 seconds
memory limit per test
256 megabytes
input
standard input
output
standard output

Petya's been bored at work and he is killing the time by watching the parking lot at the office. The parking lot looks from above like an n × m table (a cell of the table corresponds to a single parking spot). Some spots in the parking lot are taken, others are empty.

Petya watches cars riding into the parking lot one by one. After a car settles down at the parking spot, Petya amuzes himself by counting what maximum square of empty spots (i.e. a square subtable) can be seen on the parking lot if we look at it from above. Also, he takes notes of the square's size (side length) in his notebook.

You task is: given the state of the parking lot at the initial moment of time and the information about where the arriving cars park, restore what Petya wrote in his notebook. It is midday, so nobody leaves the lot.

Input

The first line contains three integers nm and k — the sizes of the parking lot and the number of arriving cars after Petya started his watch (1 ≤ n, m, k ≤ 2000). Each of the following n lines contains m characters 'X' and '.', where 'X' means a taken spot and '.' means an empty spot. Each of the next k lines contains a pair of integers xiyi — the number of row and column of the spot the corresponding car takes (1 ≤ xi ≤ n1 ≤ yi ≤ m). It is guaranteed that this place was empty. You can assume that a car enters a parking lot only after the previous car successfully finds a spot.

Output

Print k integers — the length of the side of the maximum square of empty spots after the corresponding car has entered the parking lot.

Examples
input
7 8 4 ........ X.....X. ........ ........ .X...... ........ ........ 1 5 6 4 3 5 4 6
output
5 4 4 3

 大致题意:k次操作,每次删掉一个点,删掉后问最大的不含'X'的正方形边长是多少.

分析:一道挺好的题,get了许多技巧.

          首先,题目允许离线,并且是每次删点后询问,删点后求答案比较麻烦,可以考虑时间倒流,从后往前添加点进去.类似于bzoj上一道删点求连通块数目的题. 初始化出删掉所有的k个点以后的最大正方形的边长,这个可以用dp来算.接着维护两个数组:up[i][j]和down[i][j].表示(i,j)这个点分别能往上和往下扩展多少位.这些是预处理操作.

          因为每次都往里面添加点,所以答案肯定是递增的,而答案不超过2000,所以可以while判断当前答案ans + 1后行不行,直到退出while循环,当前的ans就是答案.比添加这个点之前更大的矩形肯定包含添加进去的这个点.当判断边长为len的正方形行不行时.将所有包含当前点的正方形给枚举出来,看在这个边上的点向上扩展和向下扩展的最小值分别是多少,如果加起来-1正好 ≥ len,则可行,否则不可行.涉及到区间查询操作,可以用线段树搞一搞.对于每次添加的点,只需要在那一列改一下up和down数组,并在那一行维护一下答案就可以了.

          犯了一个错误:m写成了n.在写题的时候一般都用n而不用m,碰到这种m用的多的情况可以考虑把m,n互换.

#include 
#include
#include
#include
using namespace std;const int inf = 0x3f3f3f3f;int n,m,k,a[2010][2010],up[2010][2010],down[2010][2010],ans[2010],res,f[2010][2010];int min1[2010 << 2],min2[2010 << 2],min11,min22;char s[2010][2010];struct node{ int x,y;}e[2010];void init(){ for (int i = 1; i <= n; i++) for (int j = 1; j <= m; j++) { if (a[i][j] == 1) up[i][j] = up[i - 1][j] + 1; else up[i][j] = 0; } for (int i = n; i >= 1; i--) for (int j = 1; j <= m; j++) { if (a[i][j] == 1) down[i][j] = down[i + 1][j] + 1; else down[i][j] = 0; }}void jisuan(){ for (int i = 1; i <= n; i++) for (int j = 1; j <= m; j++) { if (a[i][j] == 0) continue; f[i][j] = min(f[i-1][j],min(f[i][j - 1],f[i-1][j-1])) + 1; res = max(res,f[i][j]); }}void pushup(int o){ min1[o] = min(min1[o * 2],min1[o * 2 + 1]); min2[o] = min(min2[o * 2],min2[o * 2 + 1]);}void build(int cur,int o,int l,int r){ if (l == r) { min1[o] = up[cur][l]; min2[o] = down[cur][l]; return; } int mid = (l + r) >> 1; build(cur,o * 2,l,mid); build(cur,o * 2 + 1,mid + 1,r); pushup(o);}int query1(int o,int l,int r,int x,int y){ if (x <= l && r <= y) return min1[o]; int mid = (l + r) >> 1,temp = inf; if (x <= mid) temp = min(temp,query1(o * 2,l,mid,x,y)); if (y > mid) temp = min(temp,query1(o * 2 + 1,mid + 1,r,x,y)); return temp;}int query2(int o,int l,int r,int x,int y){ if (x <= l && r <= y) return min2[o]; int mid = (l + r) >> 1,temp = inf; if (x <= mid) temp = min(temp,query2(o * 2,l,mid,x,y)); if (y > mid) temp = min(temp,query2(o * 2 + 1,mid + 1,r,x,y)); return temp;}bool check(int len,int y){ if (len > n || len > m) return false; for (int i = max(1,y - len + 1); i <= m - len + 1; i++) { int temp1 = query1(1,1,m,i,i + len - 1); int temp2 = query2(1,1,m,i,i + len - 1); if (temp1 + temp2 - 1 >= len) return true; } return false;}void solve(){ jisuan(); for (int i = k; i >= 1; i--) { //printf("%d\n",i); ans[i] = res; if (i == 1) break; int x = e[i].x,y = e[i].y; a[x][y] = 1; up[x][y] = up[x - 1][y] + 1; for (int j = x + 1; j <= n; j++) { if (a[j][y] == 0) break; up[j][y] += up[x][y]; } down[x][y] = down[x + 1][y] + 1; for (int j = x - 1; j >= 1; j--) { if (a[j][y] == 0) break; down[j][y] += down[x][y]; } build(x,1,1,m); while (check(res + 1,y)) res++; }}int main(){ scanf("%d%d%d",&n,&m,&k); for (int i = 1; i <= n; i++) { scanf("%s",s[i] + 1); for (int j = 1; j <= m; j++) { if (s[i][j] == '.') a[i][j] = 1; else a[i][j] = 0; } } for (int i = 1; i <= k; i++) { scanf("%d%d",&e[i].x,&e[i].y); a[e[i].x][e[i].y] = 0; } init(); solve(); for (int i = 1; i <= k; i++) printf("%d\n",ans[i]); return 0;}

 

转载于:https://www.cnblogs.com/zbtrs/p/8195865.html

你可能感兴趣的文章
STM32单片机使用注意事项
查看>>
js window.open 参数设置
查看>>
032. asp.netWeb用户控件之一初识用户控件并为其自定义属性
查看>>
移动开发平台-应用之星app制作教程
查看>>
leetcode 459. 重复的子字符串(Repeated Substring Pattern)
查看>>
springboot No Identifier specified for entity的解决办法
查看>>
浅谈 unix, linux, ios, android 区别和联系
查看>>
51nod 1428 活动安排问题 (贪心+优先队列)
查看>>
Solaris11修改主机名
查看>>
latex for wordpress(一)
查看>>
如何在maven工程中加载oracle驱动
查看>>
Flask 系列之 SQLAlchemy
查看>>
aboutMe
查看>>
【Debug】IAR在线调试时报错,Warning: Stack pointer is setup to incorrect alignmentStack,芯片使用STM32F103ZET6...
查看>>
一句话说清分布式锁,进程锁,线程锁
查看>>
FastDFS使用
查看>>
服务器解析请求的基本原理
查看>>
[HDU3683 Gomoku]
查看>>
下一代操作系统与软件
查看>>
[NOIP2013提高组] CODEVS 3287 火车运输(MST+LCA)
查看>>