• 【题解】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;
    }
    
  • 相关阅读:
    Aspnet_regiis加密web.config
    C#加密算法汇总
    ?? 运算符
    游戏外挂技术初探
    正则表达式语法
    C++Primer第四版13.5.1. 定义智能指针类的例子被new蒙蔽_BLOCK_TYPE_IS_VALID
    Adobe Flex 成为 Apache 基金会顶级开源项目
    程序员老黄历
    Flash多点触控体验和简介
    Flash开发人员必备:最新离线网页版ActionScript 3.0API文档、 flex 4.6 air 3.5 开发人员指南
  • 原文地址:https://www.cnblogs.com/yzhang-rp-inf/p/10433430.html
Copyright © 2020-2023  润新知