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。

    题解:本题思路很神~

    我们将边按编号一条一条地加到图中,如果当前边a,b所在的连通块已经连通,则我们找到这个连通块中编号最小的边,记录它的编号kick[i],并将它删去,然后将当前边加入到图中。这个可以用LCT很容易的实现。(套路:用LCT维护边权的方法,将边变成点,a-b连边视为a-c-b连边,然后图中只有从边变过来的点才有权值)

    然后采用主席树,在i的主席树中将kick[i]删除,然后查询[l,r]时再r的主席树中查询[l,r]这段区间,就能得到区间中有多少树边了。

    #include <cstdio>
    #include <cstring>
    #include <iostream>
    using namespace std;
    const int maxn=200010;
    int n,m,Q,typ,tot,ans;
    int pa[maxn],pb[maxn],f[maxn],rt[maxn],sum[maxn];
    struct LCT
    {
    	int ch[2],fa,rev,mn,val;
    }t[maxn<<1];
    struct sag
    {
    	int ls,rs,siz;
    }s[maxn*40];
    inline bool isr(int x) {return t[t[x].fa].ch[0]!=x&&t[t[x].fa].ch[1]!=x;}
    inline void rever(int x)
    {
    	swap(t[x].ch[0],t[x].ch[1]),t[x].rev^=1;
    }
    inline void pushdown(int x)
    {
    	if(t[x].rev)
    	{
    		if(t[x].ch[0])	rever(t[x].ch[0]);
    		if(t[x].ch[1])	rever(t[x].ch[1]);
    		t[x].rev=0;
    	}
    }
    inline void pushup(int x)
    {
    	t[x].mn=min(t[x].val,min(t[t[x].ch[0]].mn,t[t[x].ch[1]].mn));
    }
    inline void rotate(int x)
    {
    	int y=t[x].fa,z=t[y].fa,d=(x==t[y].ch[1]);
    	if(!isr(y))	t[z].ch[y==t[z].ch[1]]=x;
    	t[x].fa=z,t[y].fa=x,t[y].ch[d]=t[x].ch[d^1];
    	if(t[x].ch[d^1])	t[t[x].ch[d^1]].fa=y;
    	t[x].ch[d^1]=y;
    	pushup(y),pushup(x);
    }
    void updata(int x)
    {
    	if(!isr(x))	updata(t[x].fa);
    	pushdown(x);
    }
    inline void splay(int x)
    {
    	updata(x);
    	while(!isr(x))
    	{
    		int y=t[x].fa,z=t[y].fa;
    		if(!isr(y))
    		{
    			if((x==t[y].ch[1])^(y==t[z].ch[1]))	rotate(x);
    			else	rotate(y);
    		}
    		rotate(x);
    	}
    }
    inline void access(int x)
    {
    	for(int y=0;x;splay(x),t[x].ch[1]=y,pushup(x),y=x,x=t[x].fa);
    }
    inline void maker(int x)
    {
    	access(x),splay(x),rever(x);
    }
    inline void link(int a,int b)
    {
    	maker(a),t[a].fa=b;
    }
    inline void cut(int a,int b)
    {
    	maker(a),access(b),splay(b),t[a].fa=t[b].ch[0]=0,pushup(b);
    }
    void insert(int x,int &y,int l,int r,int a,int b)
    {
    	y=++tot,s[y].siz=s[x].siz+1;
    	if(l==r)	return ;
    	int mid=(l+r)>>1;
    	if(a<=mid)	s[y].rs=s[x].rs,insert(s[x].ls,s[y].ls,l,mid,a,b);
    	else	s[y].ls=s[x].ls,insert(s[x].rs,s[y].rs,mid+1,r,a,b);
    }
    int query(int x,int l,int r,int a,int b)
    {
    	if(!x||(a<=l&&r<=b))	return s[x].siz;
    	int mid=(l+r)>>1;
    	if(b<=mid)	return query(s[x].ls,l,mid,a,b);
    	if(a>mid)	return query(s[x].rs,mid+1,r,a,b);
    	return query(s[x].ls,l,mid,a,b)+query(s[x].rs,mid+1,r,a,b);
    }
    int find(int x)
    {
    	return (f[x]==x)?x:(f[x]=find(f[x]));
    }
    inline int rd()
    {
    	int ret=0,f=1;	char gc=getchar();
    	while(gc<'0'||gc>'9')	{if(gc=='-')	f=-f;	gc=getchar();}
    	while(gc>='0'&&gc<='9')	ret=ret*10+gc-'0',gc=getchar();
    	return ret*f;
    }
    int main()
    {
    	n=rd(),m=rd(),Q=rd(),typ=rd();
    	int i,a,b,c;
    	for(i=0;i<=n;i++)	f[i]=i,t[i].val=t[i].mn=m+1;
    	for(i=1;i<=m;i++)	t[i+n].val=t[i+n].mn=i;
    	for(i=1;i<=m;i++)
    	{
    		a=pa[i]=rd(),b=pb[i]=rd(),sum[i]=sum[i-1]+1;
    		if(a==b)	sum[i]--,rt[i]=rt[i-1];
    		else	if(find(a)==find(b))
    		{
    			maker(a),access(b),splay(b),c=t[b].mn;
    			insert(rt[i-1],rt[i],1,m,c,1);
    			cut(pa[c],c+n),cut(pb[c],c+n),link(a,i+n),link(b,i+n);
    		}
    		else	f[f[a]]=f[b],link(a,i+n),link(b,i+n),rt[i]=rt[i-1];
    	}
    	for(i=1;i<=Q;i++)
    	{
    		a=rd()^(ans*typ),b=rd()^(ans*typ);
    		ans=n-(sum[b]-sum[a-1]-query(rt[b],1,m,a,b));
    		printf("%d
    ",ans);
    	}
    	return 0;
    }//3 5 4 0 1 3 1 2 2 1 3 2 2 2 2 3 1 5 5 5 1 2 
  • 相关阅读:
    Android第二次作业
    六月十二课下作业
    第十三周课下作业
    第十三周上机练习
    第十二周课下作业
    第十二周上机作业
    十一周课下作业
    第十一周上机作业
    第十周上机练习
    android-7增删改查
  • 原文地址:https://www.cnblogs.com/CQzhangyu/p/7670107.html
Copyright © 2011-2022 走看看