zoukankan      html  css  js  c++  java
  • [BZOJ3514]Codechef MARCH14 GERALD07加强版 题解 [LCT+主席树]

    BZOJ3514. Codechef MARCH14 GERALD07

    Description:

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

    Input:

    ​ 第一行四个整数(N)(M)(K)(type),代表点数、边数、询问数以及询问是否加密。
    ​ 接下来(M)行,代表图中的每条边。
    ​ 接下来(K)行,每行两个整数(L)(R)代表一组询问。对于(type=0)的测试点,读入的L和R即为询问的(L)(R);对于(type=1)的测试点,每组询问的(L)(R)应为(L) (xor) (lastans)(R) (xor) (lastans)

    Output:

    (K)行每行一个整数代表该组询问的联通块个数。

    Sample Input:

    3 5 4 0
    1 3
    1 2
    2 1
    3 2
    2 2
    2 3
    1 5
    5 5
    1 2
    

    Sample Output:

    2
    1
    3
    1
    

    Hint:

    ​ 对于(100)%的数据,(1≤N、M、K≤200,000)

    题目分析:

    ​ 首先询问是在线的,因此我们需要一个数据结构动态维护图的连通性,很容易想到使用(LCT)维护当前森林的边数(sum[i]),但是(LCT)维护森林之后如何判断一段区间内的边的使用情况呢?我们可以每次(LCT)需要删边时删去编号最小的边,并用主席树来删去的边的编号在某个区间的个数。那么我们使用([L,R])这一区间的边时,为了保证连通图是一棵森林,会把一些编号在([1,L-1])的边删去,这时,我们再把([1,L-1])这些边的贡献再加回来,那么答案就是(sum[R]-sum[L-1])(+)([)在加入编号为([L,R])的边时删去的编号范围在([1,L-1])的边的数目(])

    ​ 代码如下(马蜂很丑,不喜勿喷)——

    #pragma GCC optimize(2)
    #include<bits/stdc++.h>
    #define Tp template<typename T>
    #define Ts template<typename Ty,typename... Ar>
    #define Reg register
    #define RI Reg int
    #define Con const
    #define CI Con int&
    #define I inline
    #define W while
    #define maxn 400005
    #define inf 100000000
    using namespace std;
    int n,m,q,T,ans,tot,summ[maxn],rt[maxn],tag[maxn],st[maxn],s[maxn],f[maxn],son[maxn][2],v[maxn],minn[maxn],sum[maxn*20],trl[maxn*20],trr[maxn*20],uu[maxn],vv[maxn];
    inline void rev(int x){tag[x]^=1,swap(son[x][1],son[x][0]);}
    inline bool nroot(int x){return son[f[x]][0]==x||son[f[x]][1]==x;}
    inline bool get(int x){return son[f[x]][1]==x;}
    inline void pushup(int x){
    	if(v[minn[son[x][0]]]<v[minn[son[x][1]]]) minn[x]=minn[son[x][0]];
    	else minn[x]=minn[son[x][1]];if(v[minn[x]]>v[x]) minn[x]=x;s[x]=s[son[x][0]]+s[son[x][1]]+1;
    }
    inline void pushdown(int x){if(!tag[x]) return;if(son[x][0]) rev(son[x][0]);if(son[x][1]) rev(son[x][1]);tag[x]=0;}
    inline void rotate(int x){
    	int fa=f[x],ff=f[fa],which=get(x);if(nroot(fa)) son[ff][son[ff][1]==fa]=x;son[fa][which]=son[x][which^1],son[x][which^1]=fa;
    	f[son[fa][which]]=fa,f[fa]=x,f[x]=ff;pushup(fa),pushup(x);
    }
    inline void splay(int x){
    	int y=x,top=0;st[++top]=x;while(nroot(y)) y=f[y],st[++top]=y;
    	while(top) pushdown(st[top--]);while(nroot(x)){y=f[x];if(nroot(y)) rotate(get(x)==get(y)?y:x);rotate(x);}
    }
    inline void access(int x){for(register int y=0;x;x=f[y=x]) splay(x),son[x][1]=y,pushup(x);}
    inline void makeroot(int x){access(x),splay(x),rev(x);}
    inline void split(int x,int y){makeroot(x),access(y),splay(y);}
    inline int findroot(int x){access(x),splay(x);while(son[x][0]) pushdown(x),x=son[x][0];splay(x);return x;}
    inline void link(int x,int y){makeroot(x);if(findroot(y)!=x) f[x]=y;}
    inline void cut(int x,int y){makeroot(x);if(findroot(y)==x&&s[x]==2) son[x][1]=f[y]=0,pushup(x);}
    inline void modify(int &now,int lst,int l,int r,int x){
    	now=++tot;sum[now]=sum[lst]+1;if(l==r) return;int mid=l+r>>1;
    	if(mid>=x) modify(trl[now],trl[lst],l,mid,x),trr[now]=trr[lst];
    	else modify(trr[now],trr[lst],mid+1,r,x),trl[now]=trl[lst];
    }
    inline int query(int now,int l,int r,int ll,int rr){
    	if(ll>rr) return 0;if(l>=ll&&r<=rr) return sum[now];int mid=l+r>>1,res=0;
    	if(mid>=ll) res=query(trl[now],l,mid,ll,rr);if(mid<rr) res+=query(trr[now],mid+1,r,ll,rr);return res;
    }
    class FileInputOutput
    {
    	private:
    		static const int S=1<<21;
    		#define tc() (A==B&&(B=(A=Fin)+fread(Fin,1,S,stdin),A==B)?EOF:*A++)
    		#define pc(ch) (Ftop!=Fend?*Ftop++=ch:(fwrite(Fout,1,S,stdout),*(Ftop=Fout)++=ch))
    		char Fin[S],Fout[S],*A,*B,*Ftop,*Fend; int pt[25];
    	public:
    		FileInputOutput(void) { Ftop=Fout; Fend=Fout+S; }
    		Tp inline void read(T& x)
    		{
    			x=0; char ch; while (!isdigit(ch=tc()));
    			while (x=(x<<3)+(x<<1)+(ch&15),isdigit(ch=tc()));
    		}
    		Tp inline void write(T x,const char& ch)
    		{
    			if (x<0) pc('-'),x=-x; RI ptop=0; while (pt[++ptop]=x%10,x/=10);
    			while (ptop) pc(pt[ptop--]+48); pc(ch);
    		}
    		inline void flush(void)
    		{
    			fwrite(Fout,1,Ftop-Fout,stdout);
    		}
    		#undef tc
    		#undef pc
    }F;
    int main(){
    	F.read(n),F.read(m),F.read(q),F.read(T);for(register int i=0;i<=n;i++) s[i]=1,minn[i]=i,v[i]=inf;s[0]=0;
    	for(register int i=1,x,y;i<=m;i++){
    		summ[i]=summ[i-1]+1;F.read(uu[i]),F.read(vv[i]);x=uu[i],y=vv[i];if(x==y){summ[i]--,rt[i]=rt[i-1];continue;}if(findroot(x)==findroot(y))
    		{summ[i]--,split(x,y);int num=v[minn[y]],l=uu[num],r=vv[num];modify(rt[i],rt[i-1],1,m,num),cut(num+n,l),cut(num+n,r);}
    		else rt[i]=rt[i-1];minn[i+n]=i+n,v[i+n]=i,s[i+n]=1,link(x,i+n),link(i+n,y);
    	}
    	for(register int i=1,x,y;i<=q;i++){
    		F.read(x),F.read(y);if(T==1) x^=ans,y^=ans;
    		ans=summ[y]-summ[x-1]+query(rt[y],1,m,1,x-1)-query(rt[x-1],1,m,1,x-1);ans=n-ans;F.write(ans,'
    ');
    	}
    	return F.flush(),0;
    }
    
    
  • 相关阅读:
    PowerDesigner反向工程操作步骤 以PowerDesigner15为例
    RegularExpressionValidator控件中正则表达式用法
    在C#中进行数据纵向不定行转横向列,多条信息成一行,例如员工薪资信息
    Oracle常见等待事件说明
    ORACLE 绑定变量用法总结(转)
    Configure Oracle 11gR2 RAC 一节点执行root.sh脚本报错
    ORACLE ASH/AWR
    db file sequential read 事件的优化(一)
    Redo Log Buffer的大小设置转载
    Oracle 判断 并 手动收集 统计信息 脚本
  • 原文地址:https://www.cnblogs.com/jiangxuancheng/p/14175304.html
Copyright © 2011-2022 走看看