NC231404. [NOIP2021]棋局(chess)
描述
在输了一晚上的麻将之后,小 和小 卸掉了手机上的所有牌类游戏。不过这怎么可能阻挡得了他们上课颓废的决心呢?现在他们的目光盯在了棋类游戏上,但他们两个 除了天天下飞行器以外,几乎所有棋类游戏都只懂个大概规则。
“既然我们都会玩但只能玩一点点,不如我们自己搞个缝合怪出来吧!”
游戏在一张长 行宽 列的网格形棋盘上进行,棋子落在网格的交叉点上。我们不妨记左上角的交叉点的坐标为 ,右下角的交叉点坐标为 。
棋子分为黑白两色,对局双方各执一方棋子。
每个棋子除了颜色以外还有等级,不妨设 为棋子 的颜色, 为棋子i的等级。另外,棋盘上的网格线共有 种状态,对于第 条网格线,设其状态为 。
• 对于任意 ,坐标 和 之间必须有网格线直接相连,也就是说走子必须沿着网格线走;
• 对于任意 ,必须有 ,也就是说走子过程中不能经过重复位置,特别地 ,也就是说不能原地不动(或走回原地)。
• 对于任意 ,坐标 上必须没有棋子,也就是说走子时不能越过已有的棋子。
网格线的状态含义如下所述:
• 如果 ,代表此路不通,走子时不能经过这条网格线。
• 如果 ,代表这条网格线是一条“普通道路”,每次走子时棋子最多只能经过 $1$ 条普通道路。
• 如果 ,代表这条网格线是一条“直行道路”,每次走子时棋子可以经过任意条直行道路,但只能一直沿横向或一直沿纵向走,不能转弯。如沿直行道路从 经过 走到 是可以的,但是从 经过 走到 不行。
• 如果 ,代表这条网格线是一条“互通道路”,每次走子时棋子可以经过任意条互通道路,且中途可任意转弯。
同时规定在一次走子过程中,棋子经过的网格线的状态必须全部相同,比如从 经过直行道路走到 再经过互通道路走到 是不允许的。
可怜的小 发现他的计算力不足以算出这个问题,只好向你求助。
输入描述
第一行:一个正整数 表示数据组数。对于每组数据:
第一行: 个正整数 ,分别表示棋盘的行数、列数和游戏的轮数。
接下来 行,每行为一个长 的字符串,每个字符为 中的一个, 第i行第j个字符表示交叉点 连向交叉点 的网格线状态。
接下来 行,每行为一个长 的字符串,每个字符为 中的一个, 第i行第j个字符表示交叉点 连向交叉点 的网格线状态。
接下来 行,每行 个非负整数 ,表示在第 轮有一枚颜色为 , 等级为 的棋子放在了交叉点 上。其中 表示黑子, 表示白子。保证之前交叉点 上没有棋子。
输出描述
对于每组数据输出 行,每行一个非负整数,表示第 枚棋子放置后能走到的交叉点数量。
示例1
输入:
1 3 3 5 13 22 23 010 233 0 1 2 3 1 2 2 1 1 3 1 2 0 2 3 2 1 3 2 2
输出:
4 3 3 3 2
说明:
放置棋子 后,它能走到的位置为 。
放置棋子 后,它能走到的位置为 。
放置棋子 后,它能走到的位置为 。
放置棋子 后,它能走到的位置为 。
放置棋子 后,它能走到的位置为 。
示例2
输入:
2 2 3 4 22 33 123 0 2 1 2 0 1 2 1 1 2 1 3 0 3 2 2 3 2 3 3 1 3 32 32 0 2 1 2 1 2 3 2 0 1 2 2
输出:
3 4 4 2 5 5 1
C++(clang++ 11.0.1) 解法, 执行用时: 3631ms, 内存消耗: 215088K, 提交时间: 2022-08-23 20:26:02
#include<bits/stdc++.h> using namespace std; const int N=5e5; #define x first #define y second #define pii pair<int,int> int n,m,q,idlim; int idh(int x,int y){ return x*(m+2)+y; } pii hdi(int id){ return pii(id/(m+2),id%(m+2)); } int idv(int x,int y){ return y*(n+2)+x; } pii vdi(int id){ return pii(id%(n+2),id/(n+2)); } template<class T> struct array2d{ T a[N]; int n,m; void init(int val=0){ memset(a,val,sizeof(a)); } void set_size(int n,int m,int val=0){ this->n=n; this->m=m; init(val); } T* operator[](int i){ return a+i*(m+2); } const T* operator[](int i)const{ return a+i*(m+2); } T& operator[](pii p){ return a[p.x*(m+2)+p.y]; } const T& operator[](pii p)const{ return a[p.x*(m+2)+p.y]; } }; array2d<int> v,h,col,lv,tim; vector<pii> piece; struct node{ int ch[2],sz; }; node t[N*30];int cnt; void pushup(int x){ t[x].sz=t[t[x].ch[0]].sz+t[t[x].ch[1]].sz; } void insert(int p,int &x,int l,int r){ if(!x)x=++cnt; if(l==r){ t[x].sz=1;return; } int mid=(l+r)>>1; if(p<=mid)insert(p,t[x].ch[0],l,mid); else insert(p,t[x].ch[1],mid+1,r); pushup(x); } void erase(int p,int &x,int l,int r){ if(!x)return; if(l==r){ t[x].sz=0;return; } int mid=(l+r)>>1; if(p<=mid)erase(p,t[x].ch[0],l,mid); else erase(p,t[x].ch[1],mid+1,r); pushup(x); } int merge(int x,int y){ if(!(x&&y))return x+y; t[x].ch[0]=merge(t[x].ch[0],t[y].ch[0]); t[x].ch[1]=merge(t[x].ch[1],t[y].ch[1]); if(t[x].ch[0]||t[x].ch[1])pushup(x); else t[x].sz|=t[y].sz; return x; } int query_rk(int v,int x,int l,int r){ if(!t[x].sz)return 0; if(l==r)return t[x].sz; int mid=(l+r)>>1; if(v<=mid)return query_rk(v,t[x].ch[0],l,mid); else return t[t[x].ch[0]].sz+query_rk(v,t[x].ch[1],mid+1,r); } bool exist(int v,int x,int l,int r){ if(!t[x].sz)return 0; if(l==r)return 1; int mid=(l+r)>>1; if(v<=mid)return exist(v,t[x].ch[0],l,mid); else return exist(v,t[x].ch[1],mid+1,r); } struct DSU_with_lr{ int l[N],r[N],f[N]; int _(int x){ return f[x]==x?x:f[x]=_(f[x]); } void merge(int x,int y){ x=_(x),y=_(y); if(x==y)return; f[x]=y; l[y]=min(l[y],l[x]); r[y]=max(r[y],r[x]); } int getl(int id){ return l[_(id)]; } int getr(int id){ return r[_(id)]; } bool check(int x,int y){ return _(x)==_(y); } }; DSU_with_lr hseg,vseg; struct block{ int rt0,rt1,rth,rtv; void merge(block &y){ rt0=::merge(rt0,y.rt0); rt1=::merge(rt1,y.rt1); rth=::merge(rth,y.rth); rtv=::merge(rtv,y.rtv); } int get0(int v){ return query_rk(v,rt0,1,q); } void ins0(int v){ insert(v,rt0,1,q); } void era0(int v){ erase(v,rt0,1,q); } int get1(int v){ return query_rk(v,rt1,1,q); } void ins1(int v){ insert(v,rt1,1,q); } void era1(int v){ erase(v,rt1,1,q); } void ins01(int col,int v){ col?ins1(v):ins0(v); } void era01(int col,int v){ col?era1(v):era0(v); } void insp(int x,int y){ insert(idh(x,y),rth,1,idlim); insert(idv(x,y),rtv,1,idlim); } int getsz(int col,int lv){ return t[rth].sz+(1-col?get1(lv):get0(lv)); } int geth(int x,int y1,int y2,int colx,int lvx){ auto check=[&](int p,int q){ return col[p][q]==1-colx&&lv[p][q]<=lvx&&exist(lv[p][q],1-colx?rt1:rt0,1,::q); }; return query_rk(idh(x,y2),rth,1,idlim)-query_rk(idh(x,y1-1),rth,1,idlim) +(h[x][y1-1]==2&&check(x,y1-1))+(h[x][y2]==2&&check(x,y2+1)); } int getv(int x1,int x2,int y,int colx,int lvx){ auto check=[&](int p,int q){ return col[p][q]==1-colx&&lv[p][q]<=lvx&&exist(lv[p][q],1-colx?rt1:rt0,1,::q); }; return query_rk(idv(x2,y),rtv,1,idlim)-query_rk(idv(x1-1,y),rtv,1,idlim) +(v[x1-1][y]==2&&check(x1-1,y))+(v[x2][y]==2&&check(x2+1,y)); } }; template<class T> struct DSU_array2d{ array2d<T>a; array2d<pii>f; void init(int val=0){ a.init(val); } void set_size(int n,int m,int val=0){ a.set_size(n,m,val); f.set_size(n,m,val); for(int i=1;i<=n;i++) for(int j=1;j<=m;j++) f[i][j]={i,j}; } pii _(pii x){ return x==f[x]?x:f[x]=_(f[x]); } T& operator[](pii p){ return a[_(p)]; } void merge(pii x,pii y){ x=_(x),y=_(y); if(x==y)return; a[x].merge(a[y]); f[y]=x; } }; DSU_array2d<block> b; int qsum=0; int ans[N]; int lvcnt[N]; void mian(){ cin>>n>>m>>q; v.set_size(n,m); h.set_size(n,m); col.set_size(n,m,-1); lv.set_size(n,m); tim.set_size(n,m); piece.clear(); memset(t,0,sizeof(t)); memset(&hseg,0,sizeof(hseg)); memset(&vseg,0,sizeof(vseg)); memset(lvcnt,0,sizeof(lvcnt)); b.set_size(n,m); for(int i=0;i<N;i++)hseg.l[i]=hseg.r[i]=hseg.f[i]=i; for(int i=0;i<N;i++)vseg.l[i]=vseg.r[i]=vseg.f[i]=i; idlim=(n+3)*(m+3); cnt=1; for(int i=1;i<=n;i++) for(int j=1;j<m;j++){ char c;cin>>c; h[i][j]=c-'0'; } for(int i=1;i<n;i++) for(int j=1;j<=m;j++){ char c;cin>>c; v[i][j]=c-'0'; } for(int i=1;i<=q;i++){ int colx,lvx,x,y; cin>>colx>>lvx>>x>>y; col[x][y]=colx; lv[x][y]=lvx; ++lvcnt[lvx]; tim[x][y]=i; piece.push_back(pii(x,y)); } for(int i=1;i<=q;i++)lvcnt[i]+=lvcnt[i-1]; for(int i=q-1;i>=0;--i)lv[piece[i].x][piece[i].y]=lvcnt[lv[piece[i].x][piece[i].y]]--; for(int i=1;i<=n;i++){ for(int j=1;j<m;j++){ if(h[i][j]==2&&!lv[i][j]&&!lv[i][j+1])hseg.merge(idh(i,j),idh(i,j+1)); if(h[i][j]==3&&!lv[i][j]&&!lv[i][j+1])b.merge({i,j},{i,j+1}); if(h[i][j]==3&&lv[i][j]&&!lv[i][j+1]){ b[{i,j+1}].ins01(col[i][j],lv[i][j]); } if(h[i][j]==3&&!lv[i][j]&&lv[i][j+1]){ b[{i,j}].ins01(col[i][j+1],lv[i][j+1]); } } } for(int i=1;i<n;i++){ for(int j=1;j<=m;j++){ if(v[i][j]==2&&!lv[i][j]&&!lv[i+1][j])vseg.merge(idv(i,j),idv(i+1,j)); if(v[i][j]==3&&!lv[i][j]&&!lv[i+1][j])b.merge({i,j},{i+1,j}); if(v[i][j]==3&&lv[i][j]&&!lv[i+1][j]){ b[{i+1,j}].ins01(col[i][j],lv[i][j]); } if(v[i][j]==3&&!lv[i][j]&&lv[i+1][j]){ b[{i,j}].ins01(col[i+1][j],lv[i+1][j]); } } } for(int i=1;i<=n;i++){ for(int j=1;j<=m;j++){ if(!lv[i][j]){ b[{i,j}].insp(i,j); } } } for(int i=q-1;i>=0;--i){ int ans=-1; int x=piece[i].x,y=piece[i].y; int lvx=lv[x][y],colx=col[x][y]; lv[x][y]=0; col[x][y]=-1; if(h[x][y]==2&&!lv[x][y]&&!lv[x][y+1])hseg.merge(idh(x,y),idh(x,y+1)); if(h[x][y-1]==2&&!lv[x][y-1]&&!lv[x][y])hseg.merge(idh(x,y-1),idh(x,y)); pii l=hdi(hseg.getl(idh(x,y))),r=hdi(hseg.getr(idh(x,y))); ans+=r.y-l.y+1; if(v[x][y]==2&&!lv[x][y]&&!lv[x+1][y])vseg.merge(idv(x,y),idv(x+1,y)); if(v[x-1][y]==2&&!lv[x-1][y]&&!lv[x][y])vseg.merge(idv(x-1,y),idv(x,y)); pii u=vdi(vseg.getl(idv(x,y))),d=vdi(vseg.getr(idv(x,y))); ans+=d.x-u.x+1; b[{x,y}].insp(x,y); if(h[x][y]==3){ if(!lv[x][y+1])b.merge({x,y},{x,y+1}); else b[{x,y}].ins01(col[x][y+1],lv[x][y+1]); } if(h[x][y-1]==3){ if(!lv[x][y-1])b.merge({x,y-1},{x,y}); else b[{x,y}].ins01(col[x][y-1],lv[x][y-1]); } if(v[x][y]==3){ if(!lv[x+1][y])b.merge({x,y},{x+1,y}); else b[{x,y}].ins01(col[x+1][y],lv[x+1][y]); } if(v[x-1][y]==3){ if(!lv[x-1][y])b.merge({x-1,y},{x,y}); else b[{x,y}].ins01(col[x-1][y],lv[x-1][y]); } b[{x,y}].era01(colx,lvx); ans+=b[{x,y}].getsz(colx,lvx); ans-=b[{x,y}].geth(l.x,l.y,r.y,colx,lvx); ans-=b[{x,y}].getv(u.x,d.x,u.y,colx,lvx); if(col[l.x][l.y-1]==1-colx&&h[l.x][l.y-1]==2&&lv[l.x][l.y-1]<=lvx)++ans,--l.y; if(col[r.x][r.y+1]==1-colx&&h[r.x][r.y ]==2&&lv[r.x][r.y+1]<=lvx)++ans,++r.y; if(col[u.x-1][u.y]==1-colx&&v[u.x-1][u.y]==2&&lv[u.x-1][u.y]<=lvx)++ans,--u.x; if(col[d.x+1][d.y]==1-colx&&v[d.x ][d.y]==2&&lv[d.x+1][d.y]<=lvx)++ans,++d.x; auto check=[&](int p,int q){ return !lv[p][q]||(col[p][q]==1-colx&&lv[p][q]<=lvx); }; auto vis=[&](int p,int q){ if(b._({p,q})==b._({x,y}))return 1; if(lv[p][q]&&exist(lv[p][q],col[p][q]?b[{x,y}].rt1:b[{x,y}].rt0,1,::q))return 1; return 0; }; if(h[x][y]==1&&check(x,y+1)&&!vis(x,y+1))++ans; if(v[x][y]==1&&check(x+1,y)&&!vis(x+1,y))++ans; if(h[x][y-1]==1&&check(x,y-1)&&!vis(x,y-1))++ans; if(v[x-1][y]==1&&check(x-1,y)&&!vis(x-1,y))++ans; ::ans[i]=ans; } for(int i=0;i<q;i++)cout<<ans[i]<<"\n"; qsum+=q; } int main(){ ios::sync_with_stdio(0); cin.tie(0); int T;cin>>T; while(T--){ mian(); } }