[BZOJ1453][Wc]Dface双面棋盘(lct)

17 篇文章 0 订阅

题目描述

传送门

题解

这题好麻烦啊…
相当于是有一堆砍边和加边的操作,然后询问联通块数量
维护一棵以删除时间为权值的最大生成树,这样可以保证砍断一条边一定是联通块数量-1,加一条边一定是联通块数量+1
其余的做法实际上是和二分图那道题是一样的

代码

#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\n",ans[1],ans[0]);
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值