感觉……做克老师的题,都很神仙……
还有去年一个人坐在家里写挂60分算法的惨痛记忆,凭借着一点点记忆重新写这道题。
感觉这并查集真的很神仙,仍然不会算最后的α的复杂度……自己想感觉无论如何都要挂个log
考虑到每个格子移动相当于所有障碍物反向移动,我们可以把边界也当成是障碍物,利用并查集来维护障碍物移动后位置中间还有多少个可以删减的答案,处理完这些答案就好了。
由于一共$n * m$个数据点每个最多被删减一遍,所以并不会超时。
Code:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
#include <cstdio> #include <iostream> using namespace std; typedef pair <int, int> pin; const int N = 2005; int n, m, e, qn, tot = 0, ans, f[4][N][N]; bool vis[N][N]; pin a[N << 3]; inline void read(int &X) { X = 0; char ch = 0; int op = 1; for(; ch > '9' || ch < '0'; ch = getchar()) if(ch == '-') op = -1; for(; ch >= '0' && ch <= '9'; ch = getchar()) X = (X << 3) + (X << 1) + ch - 48; X *= op; } inline void init() { for(int i = 0; i <= n + 1; i++) for(int j = 0; j <= m + 1; j++) f[0][i][j] = f[1][i][j] = i, f[2][i][j] = f[3][i][j] = j; } int find01(int x, int y, int k) { return f[k][x][y] == x ? x : f[k][x][y] = find01(f[k][x][y], y, k); } int find23(int x, int y, int k) { return f[k][x][y] == y ? y : f[k][x][y] = find23(x, f[k][x][y], k); } inline void del(int x, int y) { if(vis[x][y]) return; vis[x][y] = 1; f[0][x][y]--, f[1][x][y]++, f[2][x][y]--, f[3][x][y]++; ans++; } inline void goup(int k) { for(int i = 1; i <= tot; i++) { int x = a[i].first, y = a[i].second; a[i].first -= k; if(y < 1 || y > m || x < 1) continue; if(x > n) x = n; for(; ; ) { x = find01(x, y, 0); if(x < 1 || x < a[i].first) break; del(x, y); } } } inline void godown(int k) { for(int i = 1; i <= tot; i++) { int x = a[i].first, y = a[i].second; a[i].first += k; if(y < 1 || y > m || x > n) continue; if(x < 1) x = 1; for(; ; ) { x = find01(x, y, 1); if(x > n || x > a[i].first) break; del(x, y); } } } inline void goleft(int k) { for(int i = 1; i <= tot; i++) { int x = a[i].first, y = a[i].second; a[i].second -= k; if(x < 1 || x > n || y < 1) continue; if(y > m) y = m; for(; ; ) { y = find23(x, y, 2); if(y < 1 || y < a[i].second) break; del(x, y); } } } inline void goright(int k) { for(int i = 1; i <= tot; i++) { int x = a[i].first, y = a[i].second; a[i].second += k; if(x < 1 || x > n || y > m) continue; if(y < 1) y = 1; for(; ; ) { y = find23(x, y, 3); if(y > m || y > a[i].second) break; del(x, y); } } } int main() { read(n), read(m), read(e), read(qn); init(); for(int x, y, i = 1; i <= e; i++) { read(x), read(y); a[++tot] = pin(x, y); del(x, y); } for(int i = 1; i <= m; i++) a[++tot] = pin(0, i), a[++tot] = pin(n + 1, i); for(int i = 1; i <= n; i++) a[++tot] = pin(i, 0), a[++tot] = pin(i, m + 1); for(char op[3]; qn--; ) { scanf("%s", op); int k; read(k); ans = 0; if(op[0] == 'U') godown(k); if(op[0] == 'D') goup(k); if(op[0] == 'L') goright(k); if(op[0] == 'R') goleft(k); printf("%d ", ans); } return 0; }