zoukankan      html  css  js  c++  java
  • 【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。

    题解

    以下题解摘自《数据结构》by wfj_2048

    我们不妨先依次加边,每加入一条边(i),就把与它形成的环上的时间最早的边(j)删掉,同时设ntr[i]=j,没有删边ntr[i]=0。这个可以用(LCT)做。特殊的,对于自环,我们有ntr[i]=i。
    那么我们可以发现[l,r]的联通块个数就是n-[l,r]中ntr<l的个数。
    很显然是对的,因为ntr<l,说明它没有与之前的边形成环。而ntr>l的边与之前的边形成了环,这条边显然是不能算进去的。
    后面的查询可以用主席树维护。

    code

    #include<cstdio>
    #include<algorithm>
    using namespace std;
    const int N = 400005;
    int n,m,q,type,fa[N],ls[N],rs[N],rev[N],val[N],mn[N],Stack[N],top,u[N],v[N],ntr[N],rt[N],tot,ans;
    struct president_tree{int ls,rs,num;}t[N*30];
    int gi()
    {
    	int x=0,w=1;char ch=getchar();
    	while ((ch<'0'||ch>'9')&&ch!='-') ch=getchar();
    	if (ch=='-') w=0,ch=getchar();
    	while (ch>='0'&&ch<='9') x=(x<<3)+(x<<1)+ch-'0',ch=getchar();
    	return w?x:-x;
    }
    void pushup(int x)
    {
    	mn[x]=x;
    	if (ls[x]&&val[mn[ls[x]]]<val[mn[x]]) mn[x]=mn[ls[x]];
    	if (rs[x]&&val[mn[rs[x]]]<val[mn[x]]) mn[x]=mn[rs[x]];
    }
    bool isroot(int x){return ls[fa[x]]!=x&&rs[fa[x]]!=x;}
    void pushdown(int x){if (!rev[x]) return;swap(ls[x],rs[x]);rev[ls[x]]^=1;rev[rs[x]]^=1;rev[x]=0;}
    void R_rotate(int x)
    {
        int y=fa[x],z=fa[y];
        ls[y]=rs[x];
        if (rs[x]) fa[rs[x]]=y;
        fa[x]=z;
        if (!isroot(y)) if (y==ls[z]) ls[z]=x;else rs[z]=x;
        rs[x]=y;fa[y]=x;
        pushup(y);
    }
    void L_rotate(int x)
    {
        int y=fa[x],z=fa[y];
        rs[y]=ls[x];
        if (ls[x]) fa[ls[x]]=y;
        fa[x]=z;
        if (!isroot(y)) if (y==ls[z]) ls[z]=x;else rs[z]=x;
        ls[x]=y;fa[y]=x;
        pushup(y);
    }
    void splay(int x)
    {
        Stack[++top]=x;
        for (int i=x;!isroot(i);i=fa[i])
            Stack[++top]=fa[i];
        while (top) pushdown(Stack[top--]);
        while (!isroot(x))
        {
            int y=fa[x],z=fa[y];
            if (isroot(y))
                if (x==ls[y]) R_rotate(x);
                else L_rotate(x);
            else
                if (y==ls[z])
                    if (x==ls[y]) R_rotate(y),R_rotate(x);
                    else L_rotate(x),R_rotate(x);
                else
                    if (x==ls[y]) R_rotate(x),L_rotate(x);
                    else L_rotate(y),L_rotate(x);
        }
        pushup(x);
    }
    void access(int x){for (int y=0;x;y=x,x=fa[x]) splay(x),rs[x]=y,pushup(x);}
    void makeroot(int x){access(x);splay(x);rev[x]^=1;}
    int findroot(int x){access(x);splay(x);while (ls[x]) x=ls[x];return x;}
    void split(int x,int y){makeroot(x);access(y);splay(y);}
    void cut(int x,int y){split(x,y);fa[x]=ls[y]=0;}
    void link(int x,int y){makeroot(x);fa[x]=y;}
    
    void build(int &now,int l,int r)
    {
    	now=++tot;
    	if (l==r) return;
    	int mid=l+r>>1;
    	build(t[now].ls,l,mid);
    	build(t[now].rs,mid+1,r);
    }
    void update(int &now,int l,int r,int pos)
    {
    	t[++tot]=t[now];
    	t[now=tot].num++;
    	if (l==r) return;
    	int mid=l+r>>1;
    	if (pos<=mid) update(t[now].ls,l,mid,pos);
    	else update(t[now].rs,mid+1,r,pos);
    }
    int Query(int A,int B,int l,int r,int ql,int qr)
    {
    	if (l>=ql&&r<=qr) return t[A].num-t[B].num;
    	int mid=l+r>>1,s=0;
    	if (ql<=mid) s+=Query(t[A].ls,t[B].ls,l,mid,ql,qr);
    	if (qr>mid) s+=Query(t[A].rs,t[B].rs,mid+1,r,ql,qr);
    	return s;
    }
    int main()
    {
    	n=gi();m=gi();q=gi();type=gi();
    	for (int i=1;i<=n;i++) val[i]=1e9;
    	for (int i=1;i<=m;i++)
    	{
    		u[i]=gi();v[i]=gi();
    		if (u[i]==v[i]) {ntr[i]=i;continue;}
    		if (findroot(u[i])^findroot(v[i]))
    		{
    			val[n+i]=i;
    			link(u[i],n+i);link(v[i],n+i);
    			//printf("link %d %d through edge %d
    ",u[i],v[i],i);
    		}
    		else
    		{
    			split(u[i],v[i]);ntr[i]=mn[v[i]]-n;
    			cut(u[ntr[i]],n+ntr[i]);cut(v[ntr[i]],n+ntr[i]);
    			val[n+i]=i;
    			link(u[i],n+i);link(v[i],n+i);
    			//printf("cut edge %d between %d and %d in order to link edge %d 
    ",kan[i],u[kan[i]],v[kan[i]],i);
    		}
    	}
    	build(rt[0],0,m);
    	for (int i=1;i<=m;i++)
    	{
    		rt[i]=rt[i-1];
    		update(rt[i],0,m,ntr[i]);
    	}
    	while (q--)
    	{
    		int l=gi(),r=gi();
    		if (type) l^=ans,r^=ans;
    		ans=n-Query(rt[r],rt[l-1],0,m,0,l-1);
    		printf("%d
    ",ans);
    	}
    	return 0;
    }
    
    
  • 相关阅读:
    Dora.Interception,为.NET Core度身打造的AOP框架 [3]:多样化拦截器应用方式
    Dora.Interception,为.NET Core度身打造的AOP框架 [2]:以约定的方式定义拦截器
    Dora.Interception,为.NET Core度身打造的AOP框架 [1]:更加简练的编程体验
    TechEmpower最新一轮的性能测试出炉,ASP.NET Core依旧表现不俗
    [文章汇总]ASP.NET Core框架揭秘[最近更新:2018/10/31]
    依赖注入[8]: .NET Core DI框架[服务消费]
    依赖注入[7]: .NET Core DI框架[服务注册]
    依赖注入[6]: .NET Core DI框架[编程体验]
    依赖注入[5]: 创建一个简易版的DI框架[下篇]
    依赖注入[4]: 创建一个简易版的DI框架[上篇]
  • 原文地址:https://www.cnblogs.com/zhoushuyu/p/8137927.html
Copyright © 2011-2022 走看看