《Yuchang and Zixiang’s stones》
题意:简化下就是给定一个n * m的棋盘,有q组询问,每次询问棋子是否能放置在该位置。
能放置的条件就是,该位置之前没棋子,且该位置可以走到棋盘外。
Solution:
很明显这里是一个搜索类的问题,但是因为询问次数过多,如果对于每次询问都去搜索显然会超时。
考虑对询问离线:假定我们目前已经放置下了所有的棋子,并且处理出此时哪些位置可以走出棋盘外,哪些不能。然后我们倒序回去拆棋子。
当我们去拆这个棋子时,我们去查询它周围的点,是否可以走到棋盘外,若没有点可以,我们拆不拆除这个点都没有影响。
若周围有点可以,显然拆除后这个点也可以,那么我们拆除该点。
同时从这个点开始搜索,去更新之前无法走到,但是拆除这个点后可以走到的点。
基于上诉思路,可以发现每个点基本只会更新一次,那么时间复杂度平摊后为O(棋子数)。
可以发现此题可能存在一个点放置多次的情况,即我们回去处理的时候可能一个点处理多次,这个时候我只要去处理第一次放置这个位置的情况即可。
以下是这样处理的证明:
对于一个位置,如果它第一次放置时,就无法放置,那么显然后面再想去放置这个点更不可能可以放置,所以如果它不能放置,那么后面放置时都不会产生影响。
如果一个位置可以放置,那么当他放置后,这个位置后序将再无法放置,且很显然若这个位置可以放置,那么他放置的时间一定是最早的时间,所以对于第一次之后的放置。
也不会对结果产生影响。故只需要去最前面一次进行处理即可。
// Author: levil #include<bits/stdc++.h> using namespace std; typedef long long LL; typedef __int128_t BIG; typedef pair<int,int> pii; const int N = 1e6 + 5; const int M = 1e3 + 5; const double eps = 1e-10; const LL Mod = 4294967296; #define pi acos(-1) #define INF 1e9 #define dbg(ax) cout << "now this num is " << ax << endl; int n,m,b[4][2] = {1,0,-1,0,0,1,0,-1}; int vis[M][M]; bool isget[M][M]; void Prework() { queue<pii> Q; memset(isget,0,sizeof(isget)); for(int i = 1;i <= n;++i) { if(vis[i][1] == INF) { isget[i][1] = 1; Q.push(pii{i,1}); } if(vis[i][m] == INF) { isget[i][m] = 1; Q.push(pii{i,m}); } } for(int i = 1;i <= m;++i) { if(vis[1][i] == INF) { isget[1][i] = 1; Q.push(pii{1,i}); } if(vis[n][i] == INF) { isget[n][i] = 1; Q.push(pii{n,i}); } } while(!Q.empty()) { pii q = Q.front(); Q.pop(); for(int i = 0;i < 4;++i) { int px = q.first + b[i][0]; int py = q.second + b[i][1]; if(px >= 1 && px <= n && py >= 1 && py <= m && isget[px][py] == 0 && vis[px][py] == INF) { isget[px][py] = 1; Q.push(pii{px,py}); } } } } bool isdir(int i,int j) { if(i == 1 || i == n || j == 1 || j == m) return true; for(int k = 0;k < 4;++k) { int px = i + b[k][0]; int py = j + b[k][1]; if(px >= 1 && px <= n && py >= 1 && py <= m && isget[px][py] == 1) return true; } return false; } void cal(int sx,int sy,int id) { queue<pii> Q; Q.push(pii{sx,sy}); while(!Q.empty()) { pii q = Q.front(); Q.pop(); for(int i = 0;i < 4;++i) { int px = q.first + b[i][0]; int py = q.second + b[i][1]; if(px >= 1 && px <= n && py >= 1 && py <= m && isget[px][py] == 0 && vis[px][py] > id) { isget[px][py] = 1; Q.push(pii{px,py}); } } } } bool isu[M][M],tag[M][M]; int sum = 0,f = 0; void dfs(int x,int y) { if(f) return ; if(x == 1 || x == n || y == 1 || y == m) f = 1; if(!tag[x][y]) { tag[x][y] = 1; for(int i = 0;i < 4;++i) { int px = x + b[i][0]; int py = y + b[i][1]; if(px >= 1 && px <= n && py >= 1 && py <= m && isu[px][py] == 0) dfs(px,py); } } } bool solve2(int sx,int sy) { f = 0; memset(tag,0,sizeof(tag)); dfs(sx,sy); return f; } int x[N],y[N]; void solve() { while(~scanf("%d %d",&n,&m)) { int q;scanf("%d",&q); for(int i = 1;i <= n;++i) for(int j = 1;j <= m;++j) vis[i][j] = INF; for(int i = 1;i <= q;++i) { scanf("%d %d",&x[i],&y[i]); /* if(solve2(x[i],y[i]) && isu[x[i]][y[i]] == 0) { printf("%d is put\n",i); sum++; isu[x[i]][y[i]] = 1; }*/ vis[x[i]][y[i]] = min(i,vis[x[i]][y[i]]); } Prework(); int ans = 0; for(int i = q;i >= 1;--i) { int dx = x[i],dy = y[i]; if(i > vis[dx][dy]) continue; if(isdir(dx,dy)) { ans++; isget[dx][dy] = 1; cal(dx,dy,i); } } printf("%d\n",ans); } } int main() { solve(); // system("pause"); return 0; }