题解Luogu P4121 [WC2005]双面棋盘

Posted yzhang-rp-inf

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了题解Luogu P4121 [WC2005]双面棋盘相关的知识,希望对你有一定的参考价值。

原题传送门

这道题肥肠毒瘤qwqwq,我被卡了qwqwq

这题的正解好像是线段树+并查集,但由于我人丑常数大被卡成了70

#include <bits/stdc++.h>
#define N 205
#define getchar nc
using namespace std;
inline char nc(){
    static char buf[100000],*p1=buf,*p2=buf;
    return p1==p2&&(p2=(p1=buf)+fread(buf,1,100000,stdin),p1==p2)?EOF:*p1++;
}
inline int read()
{
    register int x=0,f=1;register char ch=getchar();
    while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
    while(ch>='0'&&ch<='9')x=(x<<3)+(x<<1)+ch-'0',ch=getchar();
    return x*f;
}
inline void write(register int x)
{
    if(!x)putchar('0');if(x<0)x=-x,putchar('-');
    static int sta[20];register int tot=0;
    while(x)sta[tot++]=x%10,x/=10;
    while(tot)putchar(sta[--tot]+48);
}
int n,m; 
int a[N][N];
struct node{
    int le[N],ri[N],lb[N],rb[N],s0,s1;
}t[N<<2];
int fa[N<<2],tmp[N<<2];
inline int father(register int x)
{
    return fa[x]==x?x:fa[x]=father(fa[x]);
}
inline void pushup(register int x)
{
    t[x].s0=t[x<<1].s0+t[x<<1|1].s0;
    t[x].s1=t[x<<1].s1+t[x<<1|1].s1;
    memcpy(t[x].lb,t[x<<1].lb,sizeof(t[x].lb));
    memcpy(t[x].rb,t[x<<1|1].rb,sizeof(t[x].rb));
    for(register int i=1;i<=n<<2;++i)
        fa[i]=i;
    for(register int i=1;i<=n;++i)
        t[x<<1|1].le[i]+=n<<1,t[x<<1|1].ri[i]+=n<<1;
    for(register int i=1;i<=n;++i)
    {
        int xx=t[x<<1].ri[i],yy=t[x<<1|1].le[i];
        if(father(xx)!=father(yy)&&t[x<<1].rb[i]==t[x<<1|1].lb[i])
        {
            fa[father(xx)]=father(yy);
            if(t[x<<1].rb[i])
                --t[x].s1;
            else
                --t[x].s0;
        }
    }
    for(register int i=1;i<=n;++i)
        t[x].le[i]=father(t[x<<1].le[i]),t[x].ri[i]=father(t[x<<1|1].ri[i]);
    for(register int i=1;i<=n;++i)
        tmp[i<<1]=t[x].le[i],tmp[(i<<1)-1]=t[x].ri[i];
    sort(tmp+1,tmp+1+(n<<1));
    int maxsum=unique(tmp+1,tmp+1+(n<<1))-tmp-1;
    for(register int i=1;i<=n;++i)
    {
        t[x].le[i]=lower_bound(tmp+1,tmp+1+maxsum,t[x].le[i])-tmp;
        t[x].ri[i]=lower_bound(tmp+1,tmp+1+maxsum,t[x].ri[i])-tmp;
    }
    for(register int i=1;i<=n;++i)
        t[x<<1|1].le[i]-=n<<1,t[x<<1|1].ri[i]-=n<<1;
}
inline void build(register int x,register int l,register int r)
{
    if(l==r)
    {
        int tot=0;
        for(register int i=1;i<=n;++i)
        {
            if(a[i][l]!=a[i-1][l])
            {
                ++tot;
                if(a[i][l])
                    ++t[x].s1;
                else
                    ++t[x].s0;
            }
            t[x].le[i]=t[x].ri[i]=tot;
            t[x].lb[i]=t[x].rb[i]=a[i][l];
        }
        return;
    }
    int mid=l+r>>1;
    build(x<<1,l,mid);
    build(x<<1|1,mid+1,r);
    pushup(x);
}
inline void change(register int x,register int l,register int r,register int pos)
{
    if(l==r)
    {
        int tot=0;
        t[x].s0=t[x].s1=0;
        for(register int i=1;i<=n;++i)
        {
            if(a[i][l]!=a[i-1][l])
            {
                ++tot;
                if(a[i][l])
                    ++t[x].s1;
                else
                    ++t[x].s0;
            }
            t[x].le[i]=t[x].ri[i]=tot;
            t[x].lb[i]=t[x].rb[i]=a[i][l];
        }
        return;
    }
    int mid=l+r>>1;
    if(pos<=mid)
        change(x<<1,l,mid,pos);
    else
        change(x<<1|1,mid+1,r,pos);
    pushup(x);
}
int main()
{
    n=read();
    for(register int i=1;i<=n;++i)
    { 
        a[0][i]=-1; 
        for(register int j=1;j<=n;++j)
            a[i][j]=read();
    } 
    build(1,1,n);
    m=read();
    while(m--)
    {
        int x=read(),y=read();
        a[x][y]^=1;
        change(1,1,n,y);
        write(t[1].s1),putchar(' '),write(t[1].s0),puts("");
    }
    return 0;
}

好像珂以用lct维护连通性?

以上是关于题解Luogu P4121 [WC2005]双面棋盘的主要内容,如果未能解决你的问题,请参考以下文章

题解Luogu P4121 [CQOI2016]手机号码

题解Luogu P4121 [CQOI2016]手机号码 数位DP

luogu P1541 乌龟棋 题解

BZOJ1453[Wc]Dface双面棋盘 线段树+并查集

[题解] luogu P1985 [USACO07OPEN]翻转棋

[Wc]Dface双面棋盘()