【题解】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维护连通性?

不用强制在线,我们珂以离线处理

计算每条边加入和删除的时间,就珂以用lct维护删除时间最靠后的生成树

代码(抄来的)

#include <bits/stdc++.h>
#define C 205
#define N 200005
#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 dx[4]={0,0,1,-1};
int dy[4]={1,-1,0,0};
int n,m,sz;
int color[C][C],c[C][C],ans[2]; 
struct data{
    int x,y,t,d,id,opt,c;
    bool operator < (const data &a) const
    {
        return x<a.x||x==a.x&&y<a.y;
    }
}e[N],opr[10005];
inline bool cmp(register data a,register data b)
{
    return a.t<b.t||(a.t==b.t&&a.opt<b.opt);
}
map <data,int> mp;
int cnt=0;
inline int eid(register int a,register int b,register int c,register int d)
{
    if(a==c)
    {
        if(b>d)
            b^=d^=b^=d;
        return (a-1)*(n-1)+b;
    }
    else
    {
        if(a>c)
            a^=c^=a^=c;
        return n*(n-1)+(a-1)*n+b;
    }
}
int f[N],ch[N][2],minn[N],rev[N],sta[N],val[N];
int re[N],pt[N],l[N],r[N],tree[N];
inline bool isroot(register int x)
{
    return ch[f[x]][0]!=x&&ch[f[x]][1]!=x;
}
inline int get(register int x)
{
    return ch[f[x]][1]==x;
}
inline void update(register int x)
{
    int loc=x;
    if(ch[x][0])
    {
        if(val[minn[ch[x][0]]]<val[loc])
            loc=minn[ch[x][0]];
    }
    if(ch[x][1])
    {
        if(val[minn[ch[x][1]]]<val[loc])
            loc=minn[ch[x][1]];
    }
    minn[x]=loc;
}
inline void pushdown(register int x)
{
    if(x&&rev[x])
    {
        if(ch[x][0]) 
            rev[ch[x][0]]^=1;
        if(ch[x][1]) 
            rev[ch[x][1]]^=1;
        ch[x][0]^=ch[x][1]^=ch[x][0]^=ch[x][1];
        rev[x]=0;
    }
}
inline void rotate(register int x)
{
    int old=f[x],oldf=f[old],wh=get(x);
    if(!isroot(old)) 
        ch[oldf][ch[oldf][1]==old]=x;
    f[x]=oldf;
    ch[old][wh]=ch[x][wh^1];
    if(ch[old][wh]) 
        f[ch[old][wh]]=old;
    ch[x][wh^1]=old;
    f[old]=x;
    update(old);
    update(x);
}
inline void splay(register int x)
{
    int top=0;
    sta[++top]=x;
    for(register int i=x;!isroot(i);i=f[i]) 
        sta[++top]=f[i];
    for(register int i=top;i;--i) 
        pushdown(sta[i]);
    for(register int fa;!isroot(x);rotate(x))
        if (!isroot(fa=f[x]))
            rotate((get(x)==get(fa))?fa:x);
}
inline void access(register int x)
{
    int t=0;
    for(;x;t=x,x=f[x])
    {
        splay(x);
        ch[x][1]=t;
        update(x);
    }
}
inline void reverse(register int x)
{
    access(x);
    splay(x);
    rev[x]^=1;
}
inline int find(register int x)
{
    access(x);
    splay(x);
    while(ch[x][0]) 
        x=ch[x][0];
    return x;
}
inline void link(register int x,register int y)
{
    reverse(x);
    f[x]=y;
}
inline void cut(register int x,register int y)
{
    reverse(x);
    access(y);
    splay(y);
    ch[y][0]=f[x]=0;
}
inline void add(register int i,register int cc)
{
    int x=e[i].x,y=e[i].y,d=e[i].d,id=e[i].id;
    if(find(x)==find(y))
    {
        reverse(x);
        access(y);
        splay(y);
        int loc=minn[y];
        if(d<=val[loc])
            return;
        cut(loc,l[loc]);
        cut(loc,r[loc]);
        tree[re[loc]]=0;
    }
    else
        --ans[cc];
    ++sz;
    val[sz]=d,re[sz]=id,pt[id]=sz,tree[id]=1;
    l[sz]=x,r[sz]=y;
    link(x,sz);
    link(y,sz);
}
inline void del(register int i)
{
    int x=e[i].x,y=e[i].y,id=e[i].id;
    cut(x,pt[id]);
    cut(y,pt[id]);
    tree[id]=0;
}
int main()
{
    n=read();
    for(register int i=1;i<=n;++i)
        for(register int j=1;j<=n;++j)
        {
            color[i][j]=c[i][j]=read();
            ++ans[c[i][j]];
        }
    for(register int i=1;i<=n;++i)
        for(register int j=1;j<=n;++j)
        {
            int num=(i-1)*n+j,cc=color[i][j];
            if(j!=n&&color[i][j+1]==cc)
                e[++cnt].x=num,e[cnt].y=num+1,e[cnt].t=0,e[cnt].id=eid(i,j,i,j+1),e[cnt].opt=1,e[cnt].c=cc;
            if(i!=n&&color[i+1][j]==cc)
                e[++cnt].x=num,e[cnt].y=num+n,e[cnt].t=0,e[cnt].id=eid(i,j,i+1,j),e[cnt].opt=1,e[cnt].c=cc;
        }
    m=read();
    for(register int i=1;i<=m;++i)
    {
        int x=read(),y=read();
        opr[i].x=x,opr[i].y=y;
        int num=(x-1)*n+y;
        for(register int j=0;j<4;++j)
        {
            int nx=x+dx[j],ny=y+dy[j],nnum=(nx-1)*n+ny;
            if(nx<=0||ny<=0||nx>n||ny>n)
                continue;
            if(c[x][y]==c[nx][ny])
                e[++cnt].x=num,e[cnt].y=nnum,e[cnt].t=i,e[cnt].id=eid(x,y,nx,ny),e[cnt].opt=-1;
            else
                e[++cnt].x=num,e[cnt].y=nnum,e[cnt].t=i,e[cnt].id=eid(x,y,nx,ny),e[cnt].opt=1;
        }
        c[x][y]^=1;
    }
    sort(e+1,e+cnt+1,cmp);
    for(register int i=1;i<=cnt;++i)
        e[i].d=m+1;
    mp.clear();
    for(register int i=cnt;i>=1;--i)
    {
        if(e[i].x>e[i].y)
            e[i].x^=e[i].y^=e[i].x^=e[i].y;
        if(mp[e[i]])
            e[i].d=mp[e[i]];
        mp[e[i]]=e[i].t;
    }
    sz=n*n;
    memset(val,127,sizeof(val));
    int now=1;
    for(;now<=cnt&&e[now].t<=0;++now)
        add(now,e[now].c);
    for(register int i=1;i<=m;++i)
    {
        int x=opr[i].x,y=opr[i].y;
        int cc=color[x][y];
        for(;now<=cnt&&e[now].t<=i;++now)
            if(e[now].opt==-1)
            {
                if(!tree[e[now].id])
                    continue;
                del(now);
                ++ans[cc];
            }
            else
                add(now,cc^1);
        --ans[cc],++ans[cc^1];
        color[x][y]^=1;
        write(ans[1]),putchar(' '),write(ans[0]),puts("");
    }
    return 0;
}
posted @ 2019-02-25 21:04  JSOI爆零珂学家yzhang  阅读(194)  评论(0编辑  收藏  举报