zoukankan      html  css  js  c++  java
  • bzoj1453[Wc]Dface双面棋盘

    一个$n*n$的棋盘,每个格子为黑色或白色。m次操作,每次修改一个格子的颜色,计算当前有多少黑色四联通块和白色四联通块

    $$1 leq n leq  200$$

    $$1 leq m leq 10000$$

    当年科技不发达...这明明是LCT一眼题啊喂

    设有$x_1$个原来与当前格子同色的连通块与当前格子断开,$x_2$个原来与当前格子不同色的连通块与当前格子连通,那么会增加$x_1-1$个当前格子原来颜色的连通块,减少$x_2-1$个当前格子现在颜色的连通块。 

    然后我们可以离线然后写一个边权LCT艹过去...

    时间复杂度$O((n+m)log_2n)$

    但是机房里的小朋友们估计连水管局长数据加长版$[bzoj2594]$都不会做...

    于是还是讲一下这道题的在线做法吧

    考虑线段树的奇怪用法(参照)

    线段树上对应$[l,r]$的节点表示棋盘第$l$行到第$r$行有多少黑色联通块和白色联通块

    同时由于这道题是四联通,有可能隔开的两个格是联通的

    会出现 黑 白 黑
                黑 黑 黑

    这种情况,所以我们考虑用并查集合并两个区间,每个点可以挂一个并查集,每次$O(n)$合并一下

    时间复杂度$O(n^3+m*nlogn)$

    Merge的时候小细节:并查集数组开4倍 用

    $1 cdots n$表示上方

    $n+1 cdots 2n$表示下方

    $1 cdots n$表示上方

    $2n+1 cdots 4n$表示右边上下方

    爆搞一下

    (但是依然钟情于LCT的我是不会写线段树套并查集的w

    #include <cstdio>
    #include <algorithm>
    #include <cstring>
    using namespace std;
     
    struct node
    {
        int b, w, f[808];
        void init (int n)
        {
            b = w = 0;
            for (int i = 0; i <= n; i++)
            f[i] = i;
        }
        int find (int x)
        {
            if (f[x] == x) return x;
            return f[x] = find(f[x]);
        }
        void merge (int a, int b)
        {
            f[find(a)] = find(b);
        }
    };
     
    int n, m;
    bool map[205][205];
     
    struct SegmentTree
    {
        node T[808];
        #define LChild p<<1,l,mid
        #define RChild p<<1|1,mid+1,r
     
        void maintain (int p, int l, int r)
        {
            int lc = p<<1, rc = lc|1, mid = (l+r)/2;
            T[p].init(n<<2);
            T[p].b = T[lc].b + T[rc].b;
            T[p].w = T[lc].w + T[rc].w;
            for (int i = 1; i <= n; i++)
            T[p].f[i] = T[lc].f[i],
            T[p].f[i+n] = T[lc].f[i+n],
            T[p].f[i+n+n] = T[rc].f[i]+n*2,
            T[p].f[i+n+n+n] = T[rc].f[i+n]+n*2;
            for (int i = 1; i <= n; i++)
            if (map[mid][i]==map[mid+1][i])
            {
                int f1 = T[p].find(i+n);
                int f2 = T[p].find(i+n+n);
                if (f1 != f2)
                {
                    T[p].w -= (map[mid][i]==0), 
                    T[p].b -= (map[mid][i]==1);
                    T[p].merge(f1,f2);
                }
            }
            for (int i = 1; i <= n; i++)
            {
                int fi = T[p].find(i);
                if (fi > n) T[p].f[fi] = T[p].f[i] = i;
            }
            for (int i = n*3+1; i <= n*4; i++)
            {
                int fi = T[p].find(i);
                if (fi <= n) T[p].f[i-n*2] = T[p].f[i];
                else T[p].f[fi] = T[p].f[i-n*2] = i-n*2;
            }
        }
     
        void make (int r, int p)
        {
            T[p].init(n<<2);
            for (int i = 1; i <= n; i++)
            T[p].merge(i,i+n);
            for (int i = 2; i <= n; i++)
            if (map[r][i]==map[r][i-1]) 
            {
                T[p].merge(i,i-1);
                T[p].merge(i+n,i+n-1);
            }
            for (int i = 1; i <= n; i++)
            if (T[p].f[i] == i) 
            T[p].w += map[r][i]==0, T[p].b += map[r][i]==1;
            for (int i = 1; i <= n; i++)
            if (T[p].f[i+n] == i+n) 
            T[p].w += map[r][i]==0, T[p].b += map[r][i]==1;
        }
     
        void build (int p, int l, int r)
        {
            if (l == r) make(r,p);
            else
            {
                int mid = (l+r)/2;
                build(LChild);
                build(RChild);
                maintain(p,l,r);
            }
        }
     
        void change (int p, int l, int r, int pos)
        {
            if (l == r) {make(r,p);return;}
            int mid = (l+r)/2;
            if (pos <= mid) change(LChild,pos);
            else change(RChild,pos);
            maintain(p,l,r);
        }
     
        void change (int x, int y)
        {
            map[x][y] = !map[x][y];
            change (1, 1, n, x);
        }
     
        void query ()
        {
            printf ("%d %d
    ", T[1].b, T[1].w);
        }
     
    }Solve;
     
    int main ()
    {
        scanf ("%d", &n);
        for (int i = 1; i <= n; i++)
        for (int j = 1; j <= n; j++)
        scanf ("%d", map[i]+j);
     
        Solve.build(1,1,n);
        scanf ("%d", &m);
        for (int i = 1; i <= m; i++)
        {
            int x, y; scanf ("%d %d", &x, &y);
            Solve.change(x,y);
            Solve.query();
        }
        return 0;
    }
    线段树套并查集
    #include<algorithm>
    #include<iostream>
    #include<cstring>
    #include<cstdio>
    #include<cmath>
    #include<map>
    using namespace std;
     
    int dx[4]={0,0,1,-1};int dy[4]={1,-1,0,0};
    int n,m,sz,color[205][205],c[205][205],cnt;
    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[200005],opr[10005];
    map <data,int> mp;
    int f[200005],ch[200005][2],minn[200005],rev[200005],stack[200005],val[200005];
    int re[200005],pt[200005],l[200005],r[200005],tree[200005];
    int ans[2];
     
    int read()
    {
        int x=0;char ch=getchar();
        while (ch<'0'||ch>'9') ch=getchar();
        while (ch>='0'&&ch<='9') x=x*10+ch-'0',ch=getchar();
        return x;
    }
    //---------------------------init----------------------------------
    int eid(int a,int b,int c,int d)
    {
        if (a==c)
        {
            if (b>d) swap(b,d);
            return (a-1)*(n-1)+b;
        }
        else
        {
            if (a>c) swap(a,c);
            return n*(n-1)+(a-1)*n+b;
        }
    }
    int cmptopt(data a,data b)
    {
        return a.t<b.t||(a.t==b.t&&a.opt<b.opt);
    }
    //----------------------------lct----------------------------------
    bool isroot(int x)
    {
        return ch[f[x]][0]!=x&&ch[f[x]][1]!=x;
    }
    int get(int x)
    {
        return ch[f[x]][1]==x;
    }
    void update(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;
    }
    void pushdown(int x)
    {
        if (x&&rev[x])
        {
            if (ch[x][0]) rev[ch[x][0]]^=1;
            if (ch[x][1]) rev[ch[x][1]]^=1;
            swap(ch[x][0],ch[x][1]);
            rev[x]=0;
        }
    }
    void rotate(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);
    }
    void splay(int x)
    {
        int top=0;stack[++top]=x;
        for (int i=x;!isroot(i);i=f[i]) stack[++top]=f[i];
        for (int i=top;i;--i) pushdown(stack[i]);
     
        for (int fa;!isroot(x);rotate(x))
            if (!isroot(fa=f[x]))
                rotate((get(x)==get(fa))?fa:x);
    }
    void access(int x)
    {
        int t=0;
        for (;x;t=x,x=f[x])
        {
            splay(x);
            ch[x][1]=t;
            update(x);
        }
    }
    void reverse(int x)
    {
        access(x);
        splay(x);
        rev[x]^=1;
    }
    int find(int x)
    {
        access(x);
        splay(x);
        while (ch[x][0]) x=ch[x][0];
        return x;
    }
    void link(int x,int y)
    {
        reverse(x);
        f[x]=y;
    }
    void cut(int x,int y)
    {
        reverse(x);
        access(y);
        splay(y);
        ch[y][0]=f[x]=0;
    }
    //--------------------------operation------------------------------
    void add(int i,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);
    }
    void del(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;
    }
     
    //---------------------------main----------------------------------
    int main()
    {
        n=read();
        for (int i=1;i<=n;++i)
            for (int j=1;j<=n;++j)
            {
                color[i][j]=c[i][j]=read();
                ++ans[c[i][j]];
            }
        for (int i=1;i<=n;++i)
            for (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 (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 (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,cmptopt);
        for (int i=1;i<=cnt;++i) e[i].d=m+1;
        mp.clear();
        for (int i=cnt;i>=1;--i)
        {
            if (e[i].x>e[i].y) swap(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 (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;
            printf("%d %d
    ",ans[1],ans[0]);
        }
    }
    LCT
  • 相关阅读:
    获取文字宽高
    jni中的参数含义
    jni开发中的常见错误
    指针只需要记住一点
    Eclipse web项目引用其它项目时的部署问题
    关于JAVA日志
    去掉Mybatis Generator生成的一堆 example
    怎样给Eclipse添加一个Xml模板
    Junit很少出现的一个问题 No tests found matching ...
    出现异常:Unsupported major.minor version
  • 原文地址:https://www.cnblogs.com/Kong-Ruo/p/8416280.html
Copyright © 2011-2022 走看看