题目大意
详细题目传送门
一个 \(n\cdot n\) 的网格 \(a\)。每个网格有传送带。其中 L
,R
,U
,D
就分别代表把传送带上的物体移动到左右上下方向的格子。如果送出了边界就代表送出去了。然后还有 ?
是代表还没有在这个网格上建传送带。
\(Q\) 次操作,每一次 将 \(a_{x,y}\) 从原先的 ?
改成四种方向中的一个传送带。求每一次操作后,假设 将其它的 ?
改成某个方向的传送带,则从每一个 \(a_{x,y}\) 开始运输,有多少个格子开始不能运输到网格外。
\(n\leq1000,Q\leq 2\cdot 10^5\)
思路
对于有一个 \(O(Qn^2)\) 的部分分是平凡的。可以发现如果从每个格子开始枚举就不现实。所以考虑将所有传送带都“反过来”,即求出从网格外开始向内做宽搜有多少个格子访问不到。对于 ?
就可以认为可以从任何地方到达。之后记录不能访问的格子数再用 \(n^2\) 减去即可。这里有暴力代码。
其实正解也差不多了。可以考虑离线。然后将整个询问反过来处理。相当于再一次正难则反。对于第一次询问(以下次数均指翻转后),直接跑一次上方暴力即可得到答案。然后对于每一次操作,相当于将原先的 \(a_{x,y}\) 从一个四向传送带改成 ?
。如果已经被访问过了答案不变,直接复制上一个询问的答案。
对于没有访问过的格子,直接考虑这个格子能否被周边已访问格子访问到。如果可以就再从 \(a_{x,y}\) 开始做暴力即可。但是因为每一个格子只会被访问一次,所以时间复杂度是 \(O(Q+n^2)\) 的。
对于正确性,即如果一个格子在上一个操作可以被访问到,在下一个操作会不会被撤销访问。发现不会,因为每一次改成的 '?' 一定会更好,这是因为对于四向和反向边,显然只有一个唯一匹配的更新操作。而对于 '?' 就充满了不确定性了。但是因为只要有一种确定路径让它出去就可以,所以相当于所有的四向格子和不确定格子只要能访问到它就一定可以直接去遍历。既继承了原先的边关系也新增了几条边,所以答案一定不会变少,每一个格子只要在之前访问过就一定会一直存在。
代码
// Problem: P11454 [USACO24DEC] 2D Conveyer Belt S
// Contest: Luogu
// URL: https://www.luogu.com.cn/problem/P11454
// Memory Limit: 256 MB
// Time Limit: 2000 ms
//
// Powered by CP Editor (https://cpeditor.org)#include <bits/stdc++.h>
#define endl "\n"
using namespace std;
typedef long long ll;
const ll MAXN=1e3+5;
ll n,Q;
ll dx[]={0,0,1,-1},dy[]={1,-1,0,0};
char C[MAXN][MAXN];
vector<pair<ll,ll>>adj;
bool vis[MAXN][MAXN];
ll dui[200][2];
ll bfs(){ll ans=0;queue<pair<ll,ll>>q;for(auto v:adj){q.push(v);//vis[v.first][v.second]=true;}while(!q.empty()){ll x=q.front().first,y=q.front().second;q.pop();if(vis[x][y]){continue;}vis[x][y]=true;//cout<<x<<" "<<y<<endl;ans++;for(int i=0;i<4;++i){ll X=x+dx[i],Y=y+dy[i];if(X<1||X>n||Y<1||Y>n||vis[X][Y]){continue;}if(C[X][Y]!='?'){if((i==0&&C[X][Y]!='L')||(i==1&&C[X][Y]!='R')||(i==2&&C[X][Y]!='U')||(i==3&&C[X][Y]!='D')){continue;}}q.push({X,Y});}}return ans;
}
struct Query{ll x,y;char op;
}q[200005];
void addf(){adj.clear();if(C[1][1]=='L'||C[1][1]=='U'||C[1][1]=='?'){adj.push_back({1,1});}for(int i=2;i<n;++i){if(C[1][i]=='?'||C[1][i]=='U'){adj.push_back({1,i});}}if(C[1][n]=='R'||C[1][n]=='U'||C[1][n]=='?'){adj.push_back({1,n});}for(int i=2;i<n;++i){if(C[i][n]=='?'||C[i][n]=='R'){adj.push_back({i,n});}}if(C[n][n]=='R'||C[n][n]=='D'||C[n][n]=='?'){adj.push_back({n,n});}for(int i=2;i<n;++i){if(C[n][i]=='?'||C[n][i]=='D'){adj.push_back({n,i});}}if(C[n][1]=='L'||C[n][1]=='D'||C[n][1]=='?'){adj.push_back({n,1});}for(int i=2;i<n;++i){if(C[i][1]=='?'||C[i][1]=='L'){adj.push_back({i,1});}}
}
ll Ans[MAXN];
signed main(){ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);cin>>n>>Q;for(int i=1;i<=n;++i){for(int j=1;j<=n;++j){C[i][j]='?';}}for(int i=1;i<=Q;++i){cin>>q[i].x>>q[i].y>>q[i].op;C[q[i].x][q[i].y]=q[i].op;}reverse(q+1,q+Q+1);addf();Ans[1]=bfs();for(int T=1;T<Q;++T){ll x=q[T].x,y=q[T].y;C[x][y]='?';if(vis[x][y]){Ans[T+1]=Ans[T];continue;}addf();//printc();for(int i=0;i<4;++i){ll X=x+dx[i],Y=y+dy[i];if(X<1||X>n||Y<1||Y>n||!vis[X][Y]){continue;}adj.push_back({x,y});break;}Ans[T+1]=Ans[T]+bfs();}for(int i=Q;i>=1;--i){cout<<n*n-Ans[i]<<endl;}return 0;
}