gmoj 6814. 【2020.10.06提高组模拟】染色大战

 这是一道sb题,但是考场时我犯了傻逼错误,导致打的程序非常麻烦非常长。

想法很简单,对于每种颜色维护一个前向星,表示与当前联通块相连通且颜色为i的连通块。

然后每次找到这个连通块,暴力将这个连通块连向的点继续丢进桶里,因为每个连通块最多进一次桶,每个位置最多遍历一次,所以可以保证时间复杂度。

#include<cstdio>
#include<cstring>
#include<map>
#include<algorithm>
#define N 1010
#define M N*N
using namespace std;
int n,m,Q,k,x,y,i,j,s[N][N],cnt,tot,bz[N][N],q[M],sum[M],fa[N][N][3],fp[M][3],ans,bzk[N][N],fx[5][3],bzp[M];
struct edge{
    int to,next;
}e[M*10];
void dfs(int x,int y){
    bz[x][y]=cnt;
    sum[cnt]++;
    int i,xx,yy;
    for (i=1;i<=4;i++){
        xx=x+fx[i][1];yy=y+fx[i][2];
        if (xx>0&&yy>0&&xx<=n&&yy<=m&&s[x][y]==s[xx][yy]&&bz[xx][yy]==0)
            fa[xx][yy][1]=x,fa[xx][yy][2]=y,dfs(xx,yy);
    }
}
void insert(int x,int y){
    tot++;
    e[tot].to=y;
    e[tot].next=q[x];
    q[x]=tot;
}
void solve(int x,int y){
    int i,xx,yy;
    for (i=1;i<=4;i++){
        xx=x+fx[i][1];yy=y+fx[i][2];
        if (xx>0&&yy>0&&xx<=n&&yy<=m){
            if (fa[xx][yy][1]==x&&fa[xx][yy][2]==y)
                solve(xx,yy);
            if (bzp[bz[xx][yy]]||s[xx][yy]==s[x][y]) continue;
            bzp[bz[xx][yy]]=1;
            insert(s[xx][yy],bz[xx][yy]);
        }
    }
}
int main(){
    freopen("color.in","r",stdin);
    freopen("color.out","w",stdout);
    fx[1][1]=1;fx[1][2]=0;
    fx[2][1]=-1;fx[2][2]=0;
    fx[3][1]=0;fx[3][2]=1;
    fx[4][1]=0;fx[4][2]=-1;
    scanf("%d%d%d%d",&n,&m,&Q,&k);
    for (i=1;i<=n;i++)
        for (j=1;j<=m;j++)
            scanf("%d",&s[i][j]);
    for (i=1;i<=n;i++)
        for (j=1;j<=m;j++)
            if (!bz[i][j]){
                cnt++;
                fp[cnt][1]=i;fp[cnt][2]=j;
                dfs(i,j);
            }
    bzp[1]=1;
    solve(1,1);
    ans=sum[1];
    while (Q--){
        scanf("%d",&x);
        for (i=q[x];i;i=e[i].next){
            y=e[i].to;
            ans+=sum[y];
            solve(fp[y][1],fp[y][2]);
        }
        q[x]=0;
        printf("%d
",ans);
    }
    return 0;
}
原文地址:https://www.cnblogs.com/Mohogany/p/13773757.html