有回档操作,考虑离线,这样就知道最终的操作序列了
发现前面的操作会被后面覆盖,干脆直接从后往前操作,如果一个位置以前染色过了那就不用再染色
所以我们可以用 $n$ 个链表维护 $n$ 个行,操作过的位置直接从链表中删除即可
然后复杂度就是 $O(nm)$,代码中是用 $n$ 个并查集来维护行,都差不多
#include<iostream> #include<cstdio> #include<algorithm> #include<cstring> #include<cmath> using namespace std; typedef long long ll; inline int read() { int x=0,f=1; char ch=getchar(); while(ch<'0'||ch>'9') { if(ch=='-') f=-1; ch=getchar(); } while(ch>='0'&&ch<='9') { x=(x<<1)+(x<<3)+(ch^48); ch=getchar(); } return x*f; } const int N=1007,M=1e5+7; int n,m,d[M][5],from[M],sav[M],tot; int mp[N][N]; struct dsu { int fa[N]; void init() { for(int i=0;i<=n+2;i++) fa[i]=i; } inline int find(int x) { return x==fa[x] ? x : fa[x]=find(fa[x]); } }g[N]; int main() { n=read(),m=read(),m=read(); for(int i=0;i<n;i++) g[i].init(); int now=0; char s[7]; for(int i=1;i<=m;i++) { scanf("%s",s+1); if(s[1]=='P') { for(int j=0;j<5;j++) d[i][j]=read(); from[i]=now; now=i; } else if(s[1]=='S') sav[++tot]=now; else now=sav[read()]; } for(int i=0;i<n;i++) for(int j=0;j<n;j++) mp[i][j]=1; int xa,ya,xb,yb,c; while(now) { c=d[now][0],xa=d[now][1],ya=d[now][2],xb=d[now][3],yb=d[now][4]; for(int i=xa;i<=xb;i+=2) for(int j=g[i].find(ya);j<=yb;j=g[i].find(j+2)) g[i].fa[j]=g[i].find(j+2),mp[i][j]=c; for(int i=xa+1;i<=xb;i+=2) for(int j=g[i].find(ya+1);j<=yb;j=g[i].find(j+2)) g[i].fa[j]=g[i].find(j+2),mp[i][j]=c; now=from[now]; } for(int i=0;i<n;i++,puts("")) for(int j=0;j<n;j++) printf("%d ",mp[i][j]); return 0; }