zoukankan      html  css  js  c++  java
  • [bzoj3514][CodeChef GERALD07] Chef ans Graph Queries [LCT+主席树]

    题面

    bzoj上的强制在线版本

    思路

    首先可以确定,这类联通块相关的询问问题,都可以$LCT$+可持久化记录解决

    用LCT维护生成树作为算法基础

    具体而言,从前往后按照边的编号顺序扫一遍边

    如果这条边两端不在同一个$LCT$联通块中,则$link$

    否则$cut$掉当前连接两条边的路径上的编号最小的边,并$link$

    记录$ntr[i]$表示第$i$条边触发第二种情况时$link$前$cut$掉的边的编号

    如果触发第一种情况,则$ntr[i]=0$

    如果为自环,则$ntr[i]=i$

    这样记录之后,建立$ntr[i]$的主席树,每次在$ntr[i]$的位置+1

    对于查询$[l,r]$,$Ans=n-query(0,l-1,root[l-1],root[r])$

    具体原因为:考虑每个$ntr$值大于等于$l$的边,显然它们在不在对答案都没有贡献(因为已经被ntr了)

    否则,它们会连接两个联通块,但是这条边不在$[l,r]$区间内,所以有联通块个数-1的贡献

    Code

    #include<iostream>
    #include<cstring>
    #include<algorithm>
    #include<cstdio>
    #define mp make_pair
    using namespace std;
    inline int read(){
        int re=0,flag=1;char ch=getchar();
    	    while(!isdigit(ch)){
    		if(ch=='-') flag=-1;
    	    	ch=getchar();
    	    }
    	    while(isdigit(ch)) re=(re<<1)+(re<<3)+ch-'0',ch=getchar();
        return re*flag;
    }
    int fa[400010],ch[400010][2],val[400010],minn[400010],rev[400010];
    void update(int x){
    	minn[x]=x;
    	if(val[minn[x]]>val[minn[ch[x][0]]]) minn[x]=minn[ch[x][0]];
    	if(val[minn[x]]>val[minn[ch[x][1]]]) minn[x]=minn[ch[x][1]];
    }
    int nroot(int x){return ((ch[fa[x]][0]==x)||(ch[fa[x]][1]==x));}
    int get(int x){return ch[fa[x]][1]==x;}
    void pushrev(int x){
    	if(!x) return;
    	swap(ch[x][0],ch[x][1]);
    	rev[x]^=1;
    }
    void pushdown(int x){
    	if(!rev[x]) return;
    	pushrev(ch[x][0]);
    	pushrev(ch[x][1]);
    	rev[x]=0;
    }
    void push(int x){
    	if(!x) return;
    	if(nroot(x)) push(fa[x]);
    	pushdown(x);
    }
    void rotate(int x){
    	int f=fa[x],ff=fa[f],son=get(x),nr=nroot(f);
    //	cout<<"		rotate "<<x<<' '<<f<<' '<<ff<<' '<<son<<' '<<ch[x][0]<<' '<<ch[x][1]<<' '<<ch[f][0]<<' '<<ch[f][1]<<'
    ';
    	ch[f][son]=ch[x][son^1];
    	if(ch[f][son]) fa[ch[f][son]]=f;
    	fa[f]=x;ch[x][son^1]=f;
    	fa[x]=ff;
    	if(nr) ch[ff][ch[ff][1]==f]=x;
    	update(f);update(x);
    }
    void splay(int x){
    //	cout<<"	splay "<<x<<'
    ';
    	push(x);
    	for(int f;nroot(x);rotate(x)){
    		f=fa[x];
    		if(nroot(f))
    			rotate((get(x)==get(f))?f:x);
    	}
    }
    void access(int x){
    //	cout<<"access "<<x<<'
    ';
    	for(int y=0;x;y=x,x=fa[x]){
    		splay(x);ch[x][1]=y;update(x);
    //		cout<<"	do "<<x<<' '<<fa[x]<<' '<<y<<'
    ';
    	}
    }
    void mroot(int x){
    	access(x);splay(x);pushrev(x);
    }
    void link(int u,int v){
    	mroot(u);fa[u]=v;
    }
    void cut(int u,int v){
    	mroot(u);access(v);splay(v);
    	fa[u]=ch[v][0]=0;
    }
    int find(int u){
    	access(u);splay(u);
    	while(ch[u][0]) u=ch[u][0];
    	return u;
    }
    int query(int u,int v){
    	mroot(u);access(v);splay(v);
    	return minn[v];
    }
    int lc[4000010],rc[4000010],seg[4000010],cnt;
    int ntr[400010],root[400010];
    int insert(int l,int r,int pre,int pos){
    	int cur=++cnt,mid=(l+r)>>1;
    	lc[cur]=lc[pre];rc[cur]=rc[pre];seg[cur]=seg[pre]+1;
    	if(l==r) return cur;
    	if(mid>=pos) lc[cur]=insert(l,mid,lc[pre],pos);
    	else rc[cur]=insert(mid+1,r,rc[pre],pos);
    	return cur;
    }
    int query(int l,int r,int ql,int qr,int pre,int cur){
    	if(l>=ql&&r<=qr) return seg[cur]-seg[pre];
    	int mid=(l+r)>>1,re=0;
    	if(mid>=ql) re+=query(l,mid,ql,qr,lc[pre],lc[cur]);
    	if(mid<qr) re+=query(mid+1,r,ql,qr,rc[pre],rc[cur]);
    	return re;
    }
    int n,m,q;
    void init(){
    	n=read();m=read();q=read();cnt=0;
    	memset(lc,0,sizeof(lc));memset(rc,0,sizeof(rc));memset(seg,0,sizeof(seg));
    	for(int i=1;i<=n;i++) fa[i]=ch[i][0]=ch[i][1]=0,minn[i]=i,val[i]=1e9,rev[i]=0;
    	val[0]=1e9;
    }
    pair<int,int>e[200010];
    int main(){
    	int T=read(),i,t1,t2,tmp,w;
    	while(T--){
    		init();
    //		cout<<n<<' '<<m<<' '<<q<<'
    ';
    		for(i=1;i<=m;i++){
    			t1=read();t2=read();
    			e[i]=mp(t1,t2);
    //			cout<<"input "<<t1<<' '<<t2<<'
    ';
    			if(t1==t2){ntr[i]=i;continue;}
    			if(find(t1)==find(t2)){
    				tmp=query(t1,t2);w=val[tmp];
    				ntr[i]=w;
    				cut(tmp,e[w].first);
    				cut(tmp,e[w].second);
    			}
    			else ntr[i]=0;
    //			cout<<"passed "<<ntr[i]<<'
    ';
    			fa[n+i]=ch[n+i][0]=ch[n+i][1]=0;
    			val[n+i]=i;minn[n+i]=n+i;rev[n+i]=0;
    			link(n+i,t1);link(n+i,t2);
    		}
    		for(i=1;i<=m;i++) root[i]=insert(0,m,root[i-1],ntr[i]);
    		for(i=1;i<=q;i++){
    			t1=read();t2=read();
    			printf("%d
    ",n-query(0,m,0,t1-1,root[t1-1],root[t2]));
    		}
    	}
    }
    
  • 相关阅读:
    一个很好的在线测试编辑器(可以在线运行很多程序)
    基于angular的route实现单页面cnodejs
    微博
    jsonp跨域再谈
    打开IIS的快捷键
    PHPCMS笔记第二弹
    phpcms ——模板标签详细使用说明
    PHP流程管理,堪比小小程序
    PHP的简单易懂文件管理,可实现基本功能
    使用php ajax写省、市、区、三级联动
  • 原文地址:https://www.cnblogs.com/dedicatus545/p/9745034.html
Copyright © 2011-2022 走看看