1 条题解
-
0
自动搬运
来自洛谷,原作者为

C1942huangjiaxu
我将终究顺流入大海搬运于
2025-08-24 22:50:14,当前版本为作者最后更新于2024-03-27 19:27:04,作者可能在搬运后再次修改,您可在原文处查看最新版自动搬运只会搬运当前题目点赞数最高的题解,您可前往洛谷题解查看更多
以下是正文
将白棋看成点,相邻的白棋之间连一条边。
如果一个棋子的周围有空位,则认为这个棋子是活棋子。
如果一个连通块中有活棋子,那么这个连通块就是活的。
答案即为死的连通块大小和,需要维护每个连通块的大小和活棋子数。
求出初始局面的答案,考虑改变一枚棋子的颜色,可能改变的只有与它相邻的连通块。
我们先把这些连通块的答案减去,改变颜色后,再把新的答案加上。
如果黑棋变为白棋,直接把相邻连通块信息合并即可,一个连通块可能有多条边与该棋子相连,注意去重。
如果白棋变为黑棋,用 tarjan 求出割点,并建立 DFS 树,分 种情况讨论。
-
如果不是割点,那么没有产生新的连通块,只需要判断该棋子是否是原先连通块唯一的活棋子即可。
-
如果是割点,会分裂出多个连通块,枚举 DFS 树中儿子分裂出去的连通块,用整个连通块的信息减去儿子分裂出去的连通块的信息,即可得到父亲所在连通块的信息。
时间复杂度 ,主要难点在代码实现上。
参考代码:
#include<bits/stdc++.h> using namespace std; const int N=1005,M=1e6+5,B=1e6+7,P=1e9+7; int dx[4]={0,1,0,-1},dy[4]={1,0,-1,0}; int T,n,id[N][N],cnt,px[M],py[M],ans,va[M],Ans; int dfn[M],low[M],co[M],tot,cl[M],Cl[M],sz[M],Sz[M]; bool ch[M],cut[M]; vector<int>e[M],g[M]; char s[N][N]; bool onb(int x,int y){ return x>0&&x<=n&&y>0&&y<=n; } bool lf(int x,int y){ for(int k=0;k<4;++k){ int i=x+dx[k],j=y+dy[k]; if(onb(i,j)&&s[i][j]=='.')return true; } return false; } void tarjan(int x){ dfn[x]=low[x]=++dfn[0],co[x]=tot,cl[x]=ch[x],sz[x]=1; for(auto v:e[x]){ if(!dfn[v]){ g[x].push_back(v); tarjan(v); low[x]=min(low[x],low[v]); if(low[v]>=dfn[x])cut[x]=true; cl[x]+=cl[v],sz[x]+=sz[v]; }else low[x]=min(low[x],dfn[v]); } } void calc(int x){ if(!Cl[co[x]])va[x]-=Sz[co[x]]; if(cut[x]){ int Rs=Sz[co[x]]-1,Rc=Cl[co[x]]-ch[x]; for(auto v:g[x])if(low[v]>=dfn[x]){ if(!cl[v])va[x]+=sz[v]; Rs-=sz[v],Rc-=cl[v]; } if(!Rc)va[x]+=Rs; }else{ if(Cl[co[x]]-ch[x]==0)va[x]+=Sz[co[x]]-1; } for(auto v:g[x])calc(v); } int rev(int i,int j){ if(s[i][j]=='o')return va[id[i][j]]; int res=0,Rs=1,Rc=lf(i,j); set<int>S; for(int k=0;k<4;++k){ int x=i+dx[k],y=j+dy[k]; if(onb(x,y)&&s[x][y]=='o')S.insert(co[id[x][y]]); } for(auto v:S){ if(!Cl[v])res-=Sz[v]; Rs+=Sz[v],Rc+=Cl[v]; } if(!Rc)res+=Rs; return res; } void solve(){ scanf("%d",&n); for(int i=1;i<=cnt;++i)e[i].clear(),g[i].clear(),co[i]=va[i]=dfn[i]=0; cnt=dfn[0]=tot=ans=Ans=0; for(int i=1;i<=n;++i)scanf("%s",s[i]+1); for(int i=1;i<=n;++i) for(int j=1;j<=n;++j)if(s[i][j]=='o'){ id[i][j]=++cnt; ch[cnt]=lf(i,j); px[cnt]=i,py[cnt]=j; } for(int i=1;i<=cnt;++i) for(int j=0;j<4;++j){ int x=px[i]+dx[j],y=py[i]+dy[j]; if(onb(x,y)&&s[x][y]=='o')e[i].push_back(id[x][y]); } for(int i=1;i<=cnt;++i)if(!co[i]){ ++tot; tarjan(i); Cl[tot]=cl[i],Sz[tot]=sz[i]; if(g[i].size()>1)cut[i]=true; else cut[i]=false; if(!cl[i])ans+=Sz[tot]; calc(i); } for(int i=1;i<=n;++i)for(int j=1;j<=n;++j)if(s[i][j]!='.'){ int t=ans+rev(i,j); Ans=(1ll*Ans*B+t)%P; } printf("%d\n",Ans); } int main(){ scanf("%d",&T); while(T--)solve(); return 0; } -
- 1
信息
- ID
- 9169
- 时间
- 3000ms
- 内存
- 256MiB
- 难度
- 6
- 标签
- 递交数
- 0
- 已通过
- 0
- 上传者