BZOJ 3514 Codechef MARCH14 GERALD07加强版

Description

N个点M条边的无向图,询问保留图中编号在[l,r]的边的时候图中的联通块个数。
(强制在线)

题解
LCT神题==
主席树只是辅助==然而并不会太敲。
这题神YY==水平太烂所以还是看了wulala的题解==
首先观察对答案的贡献。
当一条边和后面的边形成了环,那么它对答案的贡献是0。
不然就是-1咯==
所以每次加入一条边就把它能形成的环的最早的弹掉,弹不了就弹0。
LCT一发。
然后答案就是n剪掉l~r中弹出的边中小于l的个数。
主席树一发。
发现自己主席树简直弱渣。
还有LCT中rotateTM竟然敲错了==调了良久没调出来==

#include<iostream>
#include<stdio.h>
#include<string.h>
#include<algorithm>
using namespace std;
const int M=4e5+5;
int qid[M],st[M];
struct LCT{
    int tr[M][2],fa[M],mi[M],q[M],rev[M],val[M],top;
    inline bool is_root(int x){
        return tr[fa[x]][0]!=x&&tr[fa[x]][1]!=x;
    }
    inline void up(int x){
        mi[x]=x;
        if(val[mi[tr[x][0]]]<val[mi[x]])mi[x]=mi[tr[x][0]];
        if(val[mi[tr[x][1]]]<val[mi[x]])mi[x]=mi[tr[x][1]];
    }
    inline void rotate(int x){
        int y=fa[x],z=fa[y],r=tr[y][0]==x,l=r^1;
        if(!is_root(y)){
            if(tr[z][0]==y)tr[z][0]=x;
            else tr[z][1]=x;
        }
        fa[x]=z,fa[y]=x,fa[tr[x][r]]=y;
        tr[y][l]=tr[x][r],tr[x][r]=y;
        up(y);
    }
    inline void down(int x){
        if(!rev[x])return ;
        rev[tr[x][0]]^=1,rev[tr[x][1]]^=1;
        rev[x]=0;swap(tr[x][0],tr[x][1]);
    }
    void Splay(int x){
        q[++top]=x;
        for(int i=x;!is_root(i);i=fa[i])q[++top]=fa[i];
        for(;top;)down(q[top--]);
        for(;!is_root(x);){
            int y=fa[x],z=fa[y];
            if(!is_root(y)){
                if(tr[z][0]==y^tr[y][0]==x)rotate(x);
                else rotate(y);
            }
            rotate(x);
        }
        up(x);
    }
    inline void Access(int x){
        for(int t=0;x;t=x,x=fa[x])
            Splay(x),tr[x][1]=t,up(x);
    }
    inline void Make_root(int x){
        Access(x);Splay(x);rev[x]^=1;
    }
    inline void Cut(int x,int y){
        Make_root(x);Access(y);Splay(y);
        fa[x]=tr[y][0]=0;
    }
    inline int query(int x,int y){
        Make_root(x),Access(y),Splay(y);
        return mi[y];
    }
    inline void Link(int x,int y){
        Make_root(x);fa[x]=y;
    }
    inline int find(int x){
        Access(x);Splay(x);
        for(;tr[x][0];)x=tr[x][0];
        return x;
    }
}T;
struct Pre_Tree{
    int tot,ls[M*20],rs[M*20],cnt[M*20];
    inline Pre_Tree(){tot=0;}
    void Insert(int l,int r,int ot,int &tid,const int x){
        cnt[tid=++tot]=cnt[ot]+1;
        if(l==r)return;
        ls[tid]=ls[ot],rs[tid]=rs[ot];
        int mid=l+r>>1;
        if(x<=mid)Insert(l,mid,ls[ot],ls[tid],x);
        else Insert(mid+1,r,rs[ot],rs[tid],x);
    }
    int query(int lt,int rt,int l,int r,int k){
        if(r==k)return cnt[rt]-cnt[lt];
        int mid=l+r>>1;
        if(k<=mid)return query(ls[lt],ls[rt],l,mid,k);
        return query(rs[lt],rs[rt],mid+1,r,k)+cnt[ls[rt]]-cnt[ls[lt]];
    }
}PT;
inline void rd(int &a){
    a=0;char c;
    while(c=getchar(),!isdigit(c));
    do a=a*10+(c^48);
        while(c=getchar(),isdigit(c));
}
int main(){
    int n,m,q,t,u,v;
    rd(n),rd(m),rd(q),rd(t);
    int tot=n;
    for(int i=0;i<=n;++i)T.mi[i]=i,T.val[i]=1<<30;
    for(int i=1;i<=m;++i){
        rd(u),rd(v);
        if(u==v){st[i]=i;continue;}
        if(T.find(u)==T.find(v)){
            int t=T.query(u,v);
            st[i]=T.val[t];
            T.Cut(u,t),T.Cut(v,t);
        }
        T.mi[++tot]=tot,T.val[tot]=i;
        T.Link(u,tot),T.Link(v,tot);
    }
    for(int i=1;i<=m;++i)
        PT.Insert(0,m,qid[i-1],qid[i],st[i]);
    for(int lastans=0;q--;){
        rd(u),rd(v);
        if(t)u^=lastans,v^=lastans;
        printf("%d\n",lastans=n-PT.query(qid[u-1],qid[v],0,m,u-1));
    }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值