bzoj3514 Codechef MARCH14 GERALD07加强版

题目描述

题解:

貌似是LCT的套路题?

就是建主席树,然后每次形成环时将环中的第一条边送给新边作标记。

维护这种恶心东西当然用LCT了。

这道题还不同于裸一点的LCT题。本题要对于每条边新建一个节点(类似圆方树),然后将时间信息放到新建节点上。

最后每次查询只需要查标记小于l的边就行了。

因为标记小于l说明踢掉了一条不属于当前集合的边,最后剩下的只有有用的边了。

每条有用的边会干掉一个联通块。

代码:

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
#define N 200050
inline int rd()
{
    int f=1,c=0;char ch=getchar();
    while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
    while(ch>='0'&&ch<='9'){c=10*c+ch-'0';ch=getchar();}
    return f*c;
}
int n,m,K,typ,ans;
struct EG
{
    int f,t;
}e[N];
struct segtree
{
    int rt[N],tot,ls[40*N],rs[40*N],v[40*N];
    void update(int u)
    {
        v[u] = v[ls[u]] + v[rs[u]];
    }
    void insert(int l,int r,int &u,int k,int qx)
    {
        u = ++tot;
        ls[u] = ls[k],rs[u] = rs[k],v[u] = v[k]+1;
        if(l==r)return ;
        int mid = (l+r)>>1;
        if(qx<=mid)insert(l,mid,ls[u],ls[k],qx);
        else insert(mid+1,r,rs[u],rs[k],qx);
    }
    int query(int l,int r,int ul,int ur,int ql,int qr)
    {
        if(l==ql&&r==qr)return v[ur]-v[ul];
        int mid = (l+r)>>1;
        if(qr<=mid)return query(l,mid,ls[ul],ls[ur],ql,qr);
        else if(ql>mid)return query(mid+1,r,rs[ul],rs[ur],ql,qr);
        else return query(l,mid,ls[ul],ls[ur],ql,mid)+query(mid+1,r,rs[ul],rs[ur],mid+1,qr);
    }
}tr1;
struct LCT
{
    int fa[N*2],ch[N*2][2],v[N*2],mn[N*2];
    bool res[N*2];
    bool isroot(int x)
    {
        return ch[fa[x]][0]!=x&&ch[fa[x]][1]!=x;
    }
    void update(int x)
    {
        mn[x] = x;
        if(v[mn[ch[x][0]]]<v[mn[x]])mn[x]=mn[ch[x][0]];
        if(v[mn[ch[x][1]]]<v[mn[x]])mn[x]=mn[ch[x][1]];
    }
    void reser(int x)
    {
        res[x]^=1;
        swap(ch[x][0],ch[x][1]);
    }
    void pushdown(int x)
    {
        if(res[x])
        {
            reser(ch[x][0]);
            reser(ch[x][1]);
            res[x]=0;
        }
    }
    int st[N],tl;
    void down(int x)
    {
        st[tl=1]=x;
        while(!isroot(x))x=fa[x],st[++tl]=x;
        while(tl)pushdown(st[tl]),tl--;
    }
    void rotate(int x)
    {
        int y = fa[x],z = fa[y],k = (ch[y][1]==x);
        if(!isroot(y))ch[z][ch[z][1]==y]=x;
        fa[x] = z;
        ch[y][k] = ch[x][!k], fa[ch[x][!k]] = y;
        ch[x][!k] = y,fa[y] = x;
        update(y),update(x);
    }
    void splay(int x)
    {
        down(x);
        while(!isroot(x))
        {
            int y = fa[x],z = fa[y];
            if(!isroot(y))
                (ch[y][1]==x)^(ch[z][1]==y)?rotate(x):rotate(y);
            rotate(x);
        }
    }
    void access(int x)
    {
        int y = 0;
        while(x)
        {
            splay(x);
            ch[x][1]=y;
            update(x);
            y = x,x = fa[x];
        }
    }
    void mtr(int x)
    {
        access(x);
        splay(x);
        reser(x);
    }
    int findrt(int x)
    {
        access(x),splay(x);
        while(ch[x][0])x=ch[x][0];
        return x;
    }
    void link(int x,int y)
    {
        mtr(x);
        fa[x]=y;
    }
    void cut(int x,int y)
    {
        mtr(x);
        access(y);
        splay(y);
        ch[y][0]=fa[x]=0;
        update(y);
    }
    int query(int x,int y)
    {
        mtr(x);
        access(y);
        splay(y);
        return mn[y];
    }
}tr2;
int ntr[N];
void init()
{
    for(int f,t,i=1;i<=m;i++)
    {
        f = e[i].f,t = e[i].t;
        if(f==t)
        {
            ntr[i] = i;
            continue;
        }
        if(tr2.findrt(f)==tr2.findrt(t))
        {
            int tmp = tr2.query(f,t);
            int edg = tr2.v[tmp];
            tr2.cut(e[edg].f,tmp);
            tr2.cut(e[edg].t,tmp);
            ntr[i] = edg;
        }
        tr2.v[i+n] = i;
        tr2.link(i+n,f);
        tr2.link(i+n,t);
    }
    for(int i=1;i<=m;i++)
        tr1.insert(0,m,tr1.rt[i],tr1.rt[i-1],ntr[i]);
}
int main()
{
    n = rd(),m = rd(),K = rd(),typ = rd();
    for(int f,t,i=1;i<=m;i++)
    {
        f = rd(),t = rd();
        e[i].f=f,e[i].t=t;
    }
    tr2.v[0]=0x3f3f3f3f;
    for(int i=1;i<=n+m;i++)
    {
        tr2.mn[i]=i;
        tr2.v[i]=0x3f3f3f3f;
    }
    init();
    for(int l,r,i=1;i<=K;i++)
    {
        l=rd(),r=rd();
        if(typ)l^=ans,r^=ans;
        if(l>r)swap(l,r);
        ans = n-tr1.query(0,m,tr1.rt[l-1],tr1.rt[r],0,l-1);
        printf("%d\n",ans);
    }
    return 0;
}

 

转载于:https://www.cnblogs.com/LiGuanlin1124/p/10165180.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值