• bzoj3514Codechef MARCH14 GERALD07加强版


    #include <iostream>
    #include <cstdio>
    #include <cstring>
    #include <cmath>
    #include <algorithm>
    #define maxn 400005
    #define maxm 200005
    #define maxk 4000005
    using namespace std;
    
    int n,m,k,type,ans,Ans,size,fa[maxn],son[maxn][2],sm[maxn],Val[maxm],val[maxn],sum[maxk],root[maxm],lc[maxk],rc[maxk];
    bool rev[maxn];
    struct date{
        int u,v;
    }wi[maxm];
    
    struct note{
        bool which(int x){
            return son[fa[x]][1]==x;
        }
        bool isroot(int x){
            return son[fa[x]][0]!=x&&son[fa[x]][1]!=x;
        }
        void update(int x){
            sm[x]=val[x];
            if (son[x][0]) sm[x]=min(sm[x],sm[son[x][0]]);
            if (son[x][1]) sm[x]=min(sm[x],sm[son[x][1]]);
        }
        void pushdown(int x){
            if (!rev[x]) return;
            rev[x]^=1,swap(son[x][0],son[x][1]);
            if (son[x][0]) rev[son[x][0]]^=1;
            if (son[x][1]) rev[son[x][1]]^=1;
        }
        void relax(int x){
            if (!isroot(x)) relax(fa[x]);
            pushdown(x);
        }
        void rotata(int x){
            int y=fa[x],d=which(x),dd=which(y);
            if (!isroot(y)) son[fa[y]][dd]=x; fa[x]=fa[y];
            fa[son[x][d^1]]=y,son[y][d]=son[x][d^1];
            fa[y]=x,son[x][d^1]=y;
            update(y);
        }
        void splay(int x){
            relax(x);
            while (!isroot(x)){
                if (isroot(fa[x])) rotata(x);
                else if (which(x)==which(fa[x])) rotata(fa[x]),rotata(x);
                else rotata(x),rotata(x);
            }
            update(x);
        }
        void access(int x){
            for (int p=0;x;x=fa[x]){
                splay(x);
                son[x][1]=p;
                p=x;
                update(x);
            }
        }
        void make_root(int x){
            access(x);
            splay(x);
            rev[x]^=1;
        }
        void link(int x,int y){
            make_root(x);
            fa[x]=y;
        }
        void cut(int x,int y){
            make_root(x);
            access(y);
            splay(y);
            son[y][0]=fa[x]=0;
            update(y);
        }
        void split(int x,int y){
            make_root(x);
            access(y);
            splay(y);
        }
        int find_root(int x){
            access(x);
            splay(x);
            while (son[x][0]) x=son[x][0];
            return x;
        }
        int find(int x,int y){
            split(x,y);
            return sm[y];
        }
    }lct;
    
    void insert(int &k,int p,int l,int r,int x){
        k=++size,sum[k]=sum[p]+1;
        int mid=(l+r)/2;
        if (l==r) return;
        if (x<=mid) rc[k]=rc[p],insert(lc[k],lc[p],l,mid,x);
        else lc[k]=lc[p],insert(rc[k],rc[p],mid+1,r,x);
    }
    
    void insert(int id,int x){
        insert(root[id],root[id-1],0,m+1,x);
    }
    
    void Query(int k1,int k2,int l,int r,int x,int y){
        if (!k1&&!k2) return;
        if (l>=x&&r<=y){
            Ans+=(sum[k2]-sum[k1]);
            return;
        }
        int mid=(l+r)/2;
        if (x<=mid) Query(lc[k1],lc[k2],l,mid,x,y);
        if (y>mid) Query(rc[k1],rc[k2],mid+1,r,x,y);
    }
    
    int query(int x,int y){
        Ans=0;
        int u=root[x-1],v=root[y],l=0,r=m+1,mid;
        Query(u,v,l,r,0,x-1);
        return Ans;
    }
    
    int main(){
        int u,v,t1,t2,temp;
        scanf("%d%d%d%d",&n,&m,&k,&type);
        memset(sum,0,sizeof(sum));
        memset(Val,0,sizeof(Val));
        memset(fa,0,sizeof(fa));
        memset(son,0,sizeof(son));
        memset(rev,0,sizeof(rev));
        for (int i=1;i<=m;i++) scanf("%d%d",&wi[i].u,&wi[i].v);
        for (int i=1;i<=n;i++) val[i]=sm[i]=m+1;
        for (int i=1;i<=m;i++) val[n+i]=sm[n+i]=i;
        for (int i=1;i<=m;i++){
            u=wi[i].u,v=wi[i].v;
            if (u==v) Val[i]=m+1;
            if (u==v) continue;
            if (lct.find_root(u)!=lct.find_root(v)){
                Val[i]=0;
                lct.link(n+i,u),lct.link(n+i,v);
            }else{
                temp=lct.find(u,v);
                Val[i]=temp,temp+=n;
                lct.cut(temp,wi[temp-n].u),lct.cut(temp,wi[temp-n].v);
                lct.link(n+i,u),lct.link(n+i,v);
            }
        }
        memset(root,0,sizeof(root));
        for (int i=1;i<=m;i++){
            insert(i,Val[i]);
        }
        ans=0;
        for (int i=1;i<=k;i++){
            scanf("%d%d",&u,&v);
            if (type==1) u^=ans,v^=ans;
            if (u>v) swap(u,v);
            ans=n-query(u,v);
            printf("%d
    ",ans);
        }
        return 0;
    }
    View Code

    题目链接:http://www.lydsy.com/JudgeOnline/problem.php?id=3514

    题目大意:N个点M条边的无向图,询问保留图中编号在[l,r]的边的时候图中的联通块个数。

    做法:如果要求整个图中联通块的个数,记加入该边后不形成环的边数记为x,则答案为n-x,这题问的是加入编号为[l~r]中的边后联通块的个数,答案便稍微变化了一下,记能使联通块数目-1的边集为{S},答案为n-|S|,问题便成为了:有多少条边属于{S},仔细想想,可以先预处理一个数组val[i],怎么预处理呢?可以按编号依次加入边,有两种情况:*1.如果加入的这条边不形成环,则这条边的权值赋值为0,并加入这条边;*2.加入这条边形成环,记环上编号最小的边的编号为y,这加入的这条边权值为y,并删去编号最小的那条边,加入该边。这个过程用lct模拟即可,比较基础的操作。

    得出每条边的权值val[i]后,对于一个询问[L~R],如果一条边的val<l,则该边属于{S},问题便简化为一个数组val,问在区间L~R中权值在0~L-1的个数,显而易见,可持久化线段树轻松搞定。问题得以圆满解决。(Lct+可持久化线段树)

  • 相关阅读:
    Visula Studio 2013 初始化静态浮点型数据在C++类内
    catkin_make与gtest出现冲突的问题与解决
    用Visual studio2012在Windows8上开发内核驱动监视线程创建
    用Visual studio2012在Windows8上开发内核驱动监视进程创建
    TEA加密算法的C/C++实现
    说说某游戏保护驱动中驱动黑名单的具体实现
    [Windows驱动开发](四)内存管理
    [Windows驱动开发](三)基础知识——驱动例程
    [Windows驱动开发](二)基础知识——数据结构
    [Windows驱动开发](一)序言
  • 原文地址:https://www.cnblogs.com/OYzx/p/5503187.html
Copyright © 2020-2023  润新知