BZOJ 3189. [Coci2011]Slika

传送门

有回档操作,考虑离线,这样就知道最终的操作序列了

发现前面的操作会被后面覆盖,干脆直接从后往前操作,如果一个位置以前染色过了那就不用再染色

所以我们可以用 $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;
}

猜你喜欢

转载自www.cnblogs.com/LLTYYC/p/11516218.html