[bzoj3514]Codechef MARCH14 GERALD07加强版

本文深入探讨了LCT(Link Cut Tree)与线段树在解决复杂图论问题中的应用,通过具体实例[bzoj3514]CodechefMARCH14GERALD07加强版,详细解析了这两种数据结构如何高效地处理动态连通性和路径查询问题。文章涵盖了LCT的旋转、翻转操作,以及线段树的区间更新和查询技巧,为读者提供了丰富的代码实现细节。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

[bzoj3514]Codechef MARCH14 GERALD07加强版


LCT

  • 代码
#include<bits/stdc++.h>
using namespace std;
const int N=5e5+5;
const int INF=0x3f3f3f3f;
namespace LinkCutTree{
struct Splay{
    int ch[2],fa;
    int sz;bool rev;
    int val,minval;
}t[N];
int cnt,null;
int newnode(int _val){
    ++cnt;t[cnt].fa=t[cnt].ch[0]=t[cnt].ch[1]=0,t[cnt].sz=1,t[cnt].rev=0;
    t[cnt].minval=t[cnt].val=_val;
    return cnt;
}
bool isroot(int x){return t[t[x].fa].ch[0]!=x&&t[t[x].fa].ch[1]!=x;}
bool son(int x){return t[t[x].fa].ch[1]==x;}
void pushup(int x){
    t[x].sz=1,t[x].minval=t[x].val;
    if(t[x].ch[0])t[x].sz+=t[t[x].ch[0]].sz,t[x].minval=min(t[x].minval,t[t[x].ch[0]].minval);
    if(t[x].ch[1])t[x].sz+=t[t[x].ch[1]].sz,t[x].minval=min(t[x].minval,t[t[x].ch[1]].minval);
}
inline void rotate(int x){
    int f=t[x].fa,g=t[t[x].fa].fa;
    bool a=son(x),b=son(x)^1;
    if(!isroot(f))t[g].ch[son(f)]=x;
    t[x].fa=g;
    t[t[x].ch[b]].fa=f;t[f].ch[a]=t[x].ch[b];
    t[x].ch[b]=f;t[f].fa=x;
    pushup(f);pushup(x);
}
 
inline void pushnow(int x){
    if(t[x].rev) {
        swap(t[x].ch[1],t[x].ch[0]);t[x].rev=0;
        if(t[x].ch[1])t[t[x].ch[1]].rev^=1;
        if(t[x].ch[0])t[t[x].ch[0]].rev^=1;
    }
}
inline void pushdown(int x){
    if(!isroot(x))pushdown(t[x].fa);
    pushnow(x);
}
 
inline void splay(int x){
    pushdown(x);
    while(!isroot(x)){
        int f=t[x].fa;
        if(!isroot(f)){
            if(son(x)^son(f))rotate(x);
            else rotate(f);
        }
        rotate(x);
    }
}
inline void access(int x){
    int tmp=null;
    do{
        splay(x);
        t[x].ch[1]=tmp;
        pushup(x);
        tmp=x;x=t[x].fa;
    }while(x!=null);
}
inline void makeroot(int x){
    access(x);
    splay(x);
    t[x].rev^=1;
}
inline void cut(int x,int y){
    makeroot(x);
    access(y);
    splay(y);
    t[y].ch[1]=null;
    t[x].fa=null;
    pushup(y);
}
inline void link(int x,int y){
    makeroot(y);
    access(x);
    t[x].ch[1]=y;
    t[y].fa=x;
    pushup(x);
}
inline int findmin(int u,int v){
    makeroot(u);
    access(v);
    splay(v);
    return t[v].minval;
}
 
}
/*LCT*/
using namespace LinkCutTree;
int Trt[N];
namespace SegTree{
    int t[N*20],cnt,lch[N*20],rch[N*20];
    inline int add(int &x,int pre,int l,int r,int pos,int sum){
        if(!x)x=++cnt;
        int mid=(l+r)>>1;
        t[x]=t[pre]+sum;
        if(l==r)return x;
        if(pos<=mid)lch[x]=add(lch[x],lch[pre],l,mid,pos,sum),rch[x]=rch[pre];
        else rch[x]=add(rch[x],rch[pre],mid+1,r,pos,sum),lch[x]=lch[pre];
        return x;
    }
    inline int qry(int x,int l,int r,int ql,int qr){
        int mid=(l+r)>>1;
        if(!x)return 0;
        if(ql<=l&&qr>=r)return t[x];
        int ret=0;
        if(ql<=mid)
            ret+=qry(lch[x],l,mid,ql,qr);
        if(qr>mid)
            ret+=qry(rch[x],mid+1,r,ql,qr);
        return ret;
    }
}
using namespace SegTree;
int id_n[N],u[N],v[N],id_e[N];
int n,m,k,type;
 
int par[N];
inline int find(int x){
    return par[x]==x?par[x]:par[x]=find(par[x]);
}
 
int main()
{
    scanf("%d%d%d%d",&n,&m,&k,&type);
    for(int i=1;i<=n;i++){
        id_n[i]=newnode(INF);
        par[i]=i;
    }
    for(int i=1;i<=m;i++){
        scanf("%d%d",&u[i],&v[i]);
        id_e[i]=newnode(i);
        if(u[i]==v[i]){
            add(Trt[i],Trt[i-1],1,m,i,1);
            continue;
        }
        int x=find(u[i]),y=find(v[i]);
        if(x^y){
            Trt[i]=Trt[i-1];
            par[x]=y;
            link(id_n[v[i]],id_e[i]);
            link(id_n[u[i]],id_e[i]);
        }else{
            int pos=findmin(id_n[u[i]],id_n[v[i]]);
            add(Trt[i],Trt[i-1],1,m,pos,1);
            int xx=id_n[u[pos]],yy=id_n[v[pos]];
            cut(id_e[pos],xx);
            cut(id_e[pos],yy);
            link(id_e[i],id_n[u[i]]);
            link(id_e[i],id_n[v[i]]);
        }
    }
    int lastans=0;
    for(int i=1;i<=k;i++){
        int l,r;scanf("%d%d",&l,&r);
        if(type==1){
            l=l^lastans,r=r^lastans;
        }
        int ans=(r-l+1)-qry(Trt[r],1,m,l,m);
        ans=n-ans;
        printf("%d\n",ans);
        lastans=ans;
    }
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值