专栏文章
题解:P11454 [USACO24DEC] 2D Conveyer Belt S
P11454题解参与者 1已保存评论 1
文章操作
快速查看文章及其快照的属性,并进行相关操作。
- 当前评论
- 1 条
- 当前快照
- 1 份
- 快照标识符
- @miqnm63v
- 此快照首次捕获于
- 2025/12/04 07:44 3 个月前
- 此快照最后确认于
- 2025/12/04 07:44 3 个月前
这题一眼和连通性相关,就是看能不能连到矩阵外。
我们发现 Farmer John 的一次操作代表着将一个点的 连通变成了 连通,也就是说我们删掉了与一个点相连的 条边。
然后我们发现连通性和删边这一组关键词似曾相识。
于是我们想到了[JSOI2008] 星球大战的做法,开始挥舞造物主的魔法棒时光倒流。
具体来说,我们可以求出将所有操作处理完后的答案,再一步一步的将操作倒过来进行。
这样,我们就可以把删边改成加边,就可以好维护一些。
我们首先考虑如何求出所有操作完后的答案。
我们可以对于边界上的点看看能不能连出边界,如果可以就以它为起点,dfs 遍历所有能到达它的点,并打上标记,打过标记的点就不用遍历了。
然后等于询问的时光倒流,我们就看解放的那个点周围有没有可以走到外界的点(即之前打过标记的点)或是否在边界,如果有,那么这个点与所有能到达它的点都能走到外界。
时间复杂度 。
code
CPP#include<bits/stdc++.h>
#define int long long
using namespace std;
const int Q=2e5+10;
int n,m,sum;
int ans[Q];
char s[1010][1010];
int v[1010][1010];
int to[1010][1010][4];
struct Qu{
int x,y;
char ch;
}r[Q];
const int dx[]={0,0,-1,1};
const int dy[]={-1,1,0,0};
void dfs(int x,int y){
v[x][y]=1,sum++;
for(int i=0;i<4;++i){
int xx=x+dx[i],yy=y+dy[i];
if(xx<1||xx>n||yy<1||yy>n||v[xx][yy]) continue;
if(!to[xx][yy][i^1]) continue;//左^1为右,其他同理,处理能达到x点的点
dfs(xx,yy);
}
}
signed main()
{
cin>>n>>m;
for(int i=1;i<=n;i++) for(int j=1;j<=n;j++) s[i][j]='?';//一开始全部为?
for(int i=1;i<=m;i++){
cin>>r[i].x>>r[i].y>>r[i].ch;
s[r[i].x][r[i].y]=r[i].ch;//m次操作后的矩阵
}
for(int i=1;i<=n;i++){
for(int j=1;j<=n;j++){//处理出每个点是否能向每个方向走
//0代表左,1代表右,2代表上,3代表下
if(s[i][j]=='?'||s[i][j]=='L') to[i][j][0]=1;
if(s[i][j]=='?'||s[i][j]=='R') to[i][j][1]=1;
if(s[i][j]=='?'||s[i][j]=='U') to[i][j][2]=1;
if(s[i][j]=='?'||s[i][j]=='D') to[i][j][3]=1;
}
}
for(int i=1;i<=n;i++){//处理第一行
if(v[1][i]||!to[1][i][2]) continue;
dfs(1,i);
}
for(int i=1;i<=n;i++){//处理第n行
if(v[n][i]||!to[n][i][3]) continue;
dfs(n,i);
}
for(int i=1;i<=n;i++){//处理第一列
if(v[i][1]||!to[i][1][0]) continue;
dfs(i,1);
}
for(int i=1;i<=n;i++){//处理第n列
if(v[i][n]||!to[i][n][1]) continue;
dfs(i,n);
}
for(int w=m;w>=1;w--){
ans[w]=sum;
int x=r[w].x,y=r[w].y;
s[x][y]='?';
for(int i=0;i<4;i++) to[x][y][i]=1;//解放这个点
if(v[x][y]) continue;
int p=0;
for(int i=0;i<4;i++){//看看周围有没有已解放的点或是否在边界
int xx=x+dx[i],yy=y+dy[i];
if(xx<1||xx>n||yy<1||yy>n) {p=1;break;}
if(v[xx][yy]) {p=1;break;}
}
if(!p) continue;
dfs(x,y);//以这个点为起点dfs
}
for(int i=1;i<=m;i++) cout<<n*n-ans[i]<<"\n";//sum记录的是能走出去的点,所以要用总点数减去
return 0;
}
相关推荐
评论
共 1 条评论,欢迎与作者交流。
正在加载评论...