zoukankan      html  css  js  c++  java
  • BZOJ 3514 Codechef MARCH14 GERALD07加强版

    题目链接:Codechef MARCH14 GERALD07加强版

      看到这种求连边求联通块个数的题,大概思路就是计算一下有多少条边连接了两个不同的联通块,然后用总点数减一下。

      然后我们该如何判断一条边是有效边呢?我们可以先用(LCT)来维护原图,当形成环的时候就把换上最早出现的边给弹掉。我们记(a_i)表示第(i)条边弹掉的边的编号(如果没有就为(0)),那么当我们只保留编号在([l,r])内的边时,如果这其中的一条边(x)满足(a_x<l),那么这条边才是有用的。即这条边连接了两个联通块,会使得联通块个数(-1)。

      于是使用(LCT)预处理之后用主席树维护一下(a)数组就做完了。

      下面贴代码:

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #include<cmath>
    #define File(s) freopen(s".in","r",stdin),freopen(s".out","w",stdout)
    #define isroot(x) (x!=s[fa[x]][0] && x!=s[fa[x]][1])
    #define maxn 200010
    #define MAXN maxn*20
    #define INF (1<<29)
    
    using namespace std;
    typedef long long llg;
    
    struct data{
    	int u,v;
    }a[maxn];
    int n,m,q,ty,ff[maxn],d[maxn<<1],val[maxn<<1],tt;
    int fa[maxn<<1],s[maxn<<1][2],minv[maxn<<1];
    int rt[maxn],sumv[MAXN],le[MAXN],ri[MAXN],L,ans;
    bool rev[maxn<<1];
    
    int getint(){
    	int w=0;bool q=0;
    	char c=getchar();
    	while((c>'9'||c<'0')&&c!='-') c=getchar();
    	if(c=='-') c=getchar(),q=1;
    	while(c>='0'&&c<='9') w=w*10+c-'0',c=getchar();
    	return q?-w:w;
    }
    
    int find(int x){return ff[ff[x]]==ff[x]?ff[x]:ff[x]=find(ff[x]);}
    void update(int u){
    	int l=s[u][0],r=s[u][1]; minv[u]=u;
    	if(val[minv[l]]<val[minv[u]]) minv[u]=minv[l];
    	if(val[minv[r]]<val[minv[u]]) minv[u]=minv[r];
    }
    
    void rotate(int u){
    	int p=fa[u],g=fa[p];
    	bool l=(u==s[p][1]),r=!l;
    	if(!isroot(p)) s[g][p==s[g][1]]=u;
    	fa[s[u][r]]=p; s[p][l]=s[u][r];
    	s[u][r]=p; fa[p]=u; fa[u]=g;
    	update(p); update(u);
    }
    
    void splay(int u){
    	int ld=0; d[ld=1]=u;
    	for(int i=u;!isroot(i);i=fa[i]) d[++ld]=fa[i];
    	for(int i=ld,x;x=d[i],i;i--)
    		if(rev[x]){
    			rev[s[x][0]]^=1,rev[s[x][1]]^=1;
    			swap(s[x][0],s[x][1]); rev[x]=0;
    		}
    	while(!isroot(u)){
    		int p=fa[u],g=fa[p];
    		if(!isroot(p)){
    			if((u==s[p][1])^(p==s[g][1])) rotate(u);
    			else rotate(p);
    		}
    		rotate(u);
    	}
    }
    
    void access(int u){for(int t=0;u;t=u,u=fa[u]) splay(u),s[u][1]=t,update(u);}
    void makert(int u){access(u); splay(u); rev[u]^=1;}
    void link(int x,int y){makert(x); fa[x]=y;}
    void cut(int x,int y){
    	makert(x); access(y),splay(y);
    	s[y][0]=fa[x]=0; update(y);
    }
    
    int query1(int x,int y){
    	makert(x); access(y); splay(y);
    	return minv[y];
    }
    
    int add(int u,int l,int r){
    	int now=++tt,mid=(l+r)>>1;
    	sumv[now]=sumv[u]+1;
    	le[now]=le[u]; ri[now]=ri[u];
    	if(l!=r){
    		if(L<=mid) le[now]=add(le[u],l,mid);
    		else ri[now]=add(ri[u],mid+1,r);
    	}
    	return now;
    }
    
    int query2(int u,int v){
    	int l=0,r=m,mid,now=0;
    	while(l!=r){
    		mid=(l+r)>>1;
    		if(L<=mid) u=le[u],v=le[v],r=mid;
    		else now+=sumv[le[u]]-sumv[le[v]],u=ri[u],v=ri[v],l=mid+1;
    	}
    	return now;
    }
    
    int main(){
    	File("a");
    	n=getint(); m=getint(); q=getint(); ty=getint();
    	for(int i=1;i<=n;i++) ff[i]=i,val[i]=INF; val[0]=INF;
    	for(int i=1,u,v,x;i<=m;i++){
    		a[i].u=u=getint(); a[i].v=v=getint(); x=n,val[i+n]=i;
    		if(find(u)!=find(v)) ff[find(u)]=find(v);
    		else if(u!=v) x=query1(u,v),cut(a[x-n].u,x),cut(a[x-n].v,x);
    		if(u!=v) link(u,i+n),link(v,i+n); else x+=m;
    		L=x-n,rt[i]=add(rt[i-1],0,m);
    	}
    	while(q--){
    		int l=getint(),r=getint();
    		if(ty) l^=ans,r^=ans; L=l;
    		printf("%d
    ",ans=n-query2(rt[r],rt[l-1]));
    	}
    	return 0;
    }
    

      这种码农题写完就过的感觉真爽(爆数组(RE)的那一发不算)

  • 相关阅读:
    oracle sql 优化大全
    MyBatis学习笔记
    Eclipse启动项目时,删除workspaces无用的工作区间
    java 中 BigDecimal 怎么与 0 比较
    Mybatis 异常: The content of elements must consist of well-formed character data or markup
    ODS与数据仓库
    MyBatis 缓存
    管理信息系统需求调研分析指南
    Merge Into 语句代替Insert/Update在Oracle中的应用实战
    Oracle数据库常用函数使用--持续更新中
  • 原文地址:https://www.cnblogs.com/lcf-2000/p/6510922.html
Copyright © 2011-2022 走看看