• [bzoj3514]Codechef MARCH14 GERALD07加强版——lct+主席树


    题目大意

    给定一个图,求编号在[l,r]之间的边形成的图的连通块个数。

    思路

    考虑一条边什么时候会造成贡献,即这条边相连的两个部分在之前从未连通过,或者是把所有编号小于l的边去掉之后这两个部分未连通。

    对于第一种情况可以轻松地用并查集来实现。

    对于第二种情况,对于每一个l,我们需要判断出u,v这两个点的所有路径中是否存在一条路径使得min(id)>=l,如果不存在则(u,v)这条边可以造成一次贡献,不难发现我们只需要处理出加入(u,v)这条边时以编号为权值的最大生成树,环上最小的那条边的编号即是否造成贡献的临界点,假设环上最小的边的编号为x,如果l<=x那么无论如何都可以连通,否则总有一条边不在[l,r]之间。

    上述算法可以轻松地用lct+主席树来维护。

    /*=======================================
     * Author : ylsoi
     * Time : 2019.3.31
     * Problem : bzoj3514
     * E-mail : ylsoi@foxmail.com
     * ====================================*/
    #include<bits/stdc++.h>
    
    #define REP(i,a,b) for(int i=a,i##_end_=b;i<=i##_end_;++i)
    #define DREP(i,a,b) for(int i=a,i##_end_=b;i>=i##_end_;--i)
    #define debug(x) cout<<#x<<"="<<x<<" "
    #define fi first
    #define se second
    #define mk make_pair
    #define pb push_back
    #define pii pair<int,int>
    typedef long long ll;
    
    using namespace std;
    
    void File(){
    	freopen("bzoj3514.in","r",stdin);
    	freopen("bzoj3514.out","w",stdout);
    }
    
    template<typename T>void read(T &_){
    	_=0; T f=1; char c=getchar();
    	for(;!isdigit(c);c=getchar())if(c=='-')f=-1;
    	for(;isdigit(c);c=getchar())_=(_<<1)+(_<<3)+(c^'0');
    	_*=f;
    }
    
    string proc(){
    	ifstream f("/proc/self/status");
    	return string(istreambuf_iterator<char>(f),istreambuf_iterator<char>());
    }
    
    const int maxn=2e5+10;
    const int inf=0x3f3f3f3f;
    int n,m,q,ty;
    int cnt_seg;
    pii e[maxn];
    
    struct lct{
    #define lc ch[o][0]
    #define rc ch[o][1]
    	int ch[maxn<<1][2],fa[maxn<<1],tg[maxn<<1];
    	int stk[maxn<<1],w[maxn<<1],mn[maxn<<1];
    	void pushup(int o){
    		mn[o]=w[o];
    		if(lc)mn[o]=min(mn[o],mn[lc]);
    		if(rc)mn[o]=min(mn[o],mn[rc]);
    	}
    	void pushdown(int o){
    		if(!tg[o])return;
    		if(lc)tg[lc]^=1;
    		if(rc)tg[rc]^=1;
    		tg[o]=0,swap(lc,rc);
    	}
    	int rel(int o){return ch[fa[o]][1]==o;}
    	int isrt(int o){return ch[fa[o]][0]!=o && ch[fa[o]][1]!=o;}
    	void rotate(int o){
    		int f=fa[o],r=rel(o);
    		fa[o]=fa[f]; if(!isrt(f))ch[fa[f]][rel(f)]=o;
    		fa[ch[o][r^1]]=f; ch[f][r]=ch[o][r^1];
    		fa[f]=o; ch[o][r^1]=f;
    		pushup(f),pushup(o);
    	}
    	void splay(int o){
    		int p=o,tp=0;
    		while(true){
    			stk[++tp]=p;
    			if(isrt(p))break;
    			p=fa[p];
    		}
    		DREP(i,tp,1)pushdown(stk[i]);
    		for(int f;!isrt(o);rotate(o))
    			if(!isrt(f=fa[o]))rotate(rel(o)==rel(f) ? f : o);
    	}
    	void access(int o){
    		for(int res=0;o;o=fa[o]){
    			splay(o),ch[o][1]=res,pushup(o),res=o;
    		}
    	}
    	void mkrt(int o){access(o),splay(o),tg[o]^=1;}
    	void split(int x,int y){mkrt(x),access(y),splay(y);}
    	void link(int x,int y){mkrt(x),fa[x]=y;}
    	void cut(int x,int y){split(x,y),ch[y][0]=0,fa[x]=0,pushup(y);}
    	int query(int x,int y){split(x,y);return mn[y];}
    #undef lc
    #undef rc
    }T;
    
    #define mid ((l+r)>>1)
    
    struct node{
    	int lc,rc,sum;
    }t[maxn*20];
    int root[maxn];
    
    void insert(int &o,int l,int r,int p){
    	int now=++cnt_seg;
    	t[now]=t[o],o=now,++t[o].sum;
    	if(l==r)return;
    	if(p<=mid)insert(t[o].lc,l,mid,p);
    	else insert(t[o].rc,mid+1,r,p);
    }
    
    int query(int o1,int o2,int l,int r,int L,int R){
    	int sum=t[o2].sum-t[o1].sum;
    	if(!sum || (L<=l && r<=R))return sum;
    	sum=0;
    	if(L<=mid)sum+=query(t[o1].lc,t[o2].lc,l,mid,L,R);
    	if(R>=mid+1)sum+=query(t[o1].rc,t[o2].rc,mid+1,r,L,R);
    	return sum;
    }
    
    #undef mid
    
    int fa[maxn];
    int find(int x){return fa[x]==x ? x : fa[x]=find(fa[x]);}
    
    int main(){
    	File();
    
    	read(n),read(m),read(q),read(ty);
    	REP(i,1,n)fa[i]=i;
    
    	REP(i,1,n)T.w[i]=T.mn[i]=inf;
    
    	int u,v;
    	REP(i,1,m){
    		read(u),read(v);
    		e[i]=mk(u,v);
    		T.w[i+n]=T.mn[i+n]=i;
    		root[i]=root[i-1];
    		if(u==v)continue;
    		else if(find(u)!=find(v)){
    			fa[find(u)]=find(v);
    			insert(root[i],0,m,0);
    		}
    		else{
    			int mn=T.query(u,v);
    			insert(root[i],0,m,mn);
    			T.cut(mn+n,e[mn].fi);
    			T.cut(mn+n,e[mn].se);
    		}
    		T.link(i+n,u);
    		T.link(i+n,v);
    	}
    
    	int las=0;
    	REP(i,1,q){
    		read(u),read(v);
    		if(ty)u^=las,v^=las;
    		las=n-query(root[u-1],root[v],0,m,0,u-1);
    		printf("%d
    ",las);
    	}
    
    	return 0;
    }
    
    
  • 相关阅读:
    使用bottle进行web开发(2):http request
    使用bottle进行web开发(1):hello world
    python modules
    python的class的__str__和__repr__(转)
    functools模块方法学习(1):partial
    bottle框架学习(2):变量定义等
    VisualSVN_Server安装_配置图文教程
    管理的艺术--达尔文进化论:适者生存 末位淘汰
    LINUX怎么修改IP地址
    Cent OS 命令行和窗口界面默认登录切换方法
  • 原文地址:https://www.cnblogs.com/ylsoi/p/10632067.html
Copyright © 2020-2023  润新知