zoukankan      html  css  js  c++  java
  • BZOJ3514: Codechef MARCH14 GERALD07加强版

    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。

    2016.2.26提高时限至60s

    题解Here!

    首先把边依次加到图中,若当前这条边与图中的边形成了环,那么把这个环中最早加进来的边弹出去,并将每条边把哪条边弹了出去记录下来:add_time[i] = j;

    特别地,要是没有弹出边,add_time[i] = 0;
    这个显然是可以用LCT来弄的对吧。
    然后对于每个询问,我们的答案就是对l~r中add_time小于l的边求和,并用n减去这个值。

    对于查询从l ~ r中有多少边的add_time小于l,我用的是主席树。

    附代码:

    #include<iostream>
    #include<algorithm>
    #include<cstdio>
    #define MAXN 400010
    #define MAX (1<<30)
    using namespace std;
    int n,m,q;
    int val[MAXN],root[MAXN],add_time[MAXN];
    bool k;
    struct Graph{
        int x,y;
    }a[MAXN];
    inline int read(){
        int date=0,w=1;char c=0;
        while(c<'0'||c>'9'){if(c=='-')w=-1;c=getchar();}
        while(c>='0'&&c<='9'){date=date*10+c-'0';c=getchar();}
        return date*w;
    }
    namespace LCT{
        int top=0,stack[MAXN];
        struct Link_Cut_Tree{
            int son[2];
            int f,v,flag;
        }a[MAXN];
        inline bool isroot(int rt){
            return a[a[rt].f].son[0]!=rt&&a[a[rt].f].son[1]!=rt;
        }
        inline void pushup(int rt){
            if(!rt)return;
            a[rt].v=rt;
            if(val[a[rt].v]>val[a[a[rt].son[0]].v])a[rt].v=a[a[rt].son[0]].v;
            if(val[a[rt].v]>val[a[a[rt].son[1]].v])a[rt].v=a[a[rt].son[1]].v;
        }
        inline void pushdown(int rt){
            if(!rt||!a[rt].flag)return;
            a[a[rt].son[0]].flag^=1;a[a[rt].son[1]].flag^=1;a[rt].flag^=1;
            swap(a[rt].son[0],a[rt].son[1]);
        }
        inline void turn(int rt){
            int x=a[rt].f,y=a[x].f,k=a[x].son[0]==rt?1:0;
            if(!isroot(x)){
                if(a[y].son[0]==x)a[y].son[0]=rt;
                else a[y].son[1]=rt;
            }
            a[rt].f=y;a[x].f=rt;a[a[rt].son[k]].f=x;
            a[x].son[k^1]=a[rt].son[k];a[rt].son[k]=x;
            pushup(x);pushup(rt);
        }
        void splay(int rt){
            top=0;
            stack[++top]=rt;
            for(int i=rt;!isroot(i);i=a[i].f)stack[++top]=a[i].f;
            while(top)pushdown(stack[top--]);
            while(!isroot(rt)){
                int x=a[rt].f,y=a[x].f;
                if(!isroot(x)){
                    if((a[y].son[0]==x)^(a[x].son[0]==rt))turn(rt);
                    else turn(x);
                }
                turn(rt);
            }
        }
        void access(int rt){
            for(int i=0;rt;i=rt,rt=a[rt].f){
                splay(rt);
                a[rt].son[1]=i;
                pushup(rt);
            }
        }
        inline void makeroot(int rt){access(rt);splay(rt);a[rt].flag^=1;}
        int find(int rt){
            access(rt);splay(rt);
            while(a[rt].son[0])rt=a[rt].son[0];
            return rt;
        }
        inline void split(int x,int y){makeroot(x);access(y);splay(y);}
        inline void link(int x,int y){makeroot(x);a[x].f=y;}
        inline void cut(int x,int y){split(x,y);a[x].f=a[y].son[0]=0;}
        inline int query(int x,int y){split(x,y);return a[y].v;}
    }
    namespace CT{
        int size=1;
        struct Charman_Tree{
            int l,r,sum;
        }a[MAXN*40];
        inline void buildtree(){
            root[0]=0;
            a[0].l=a[0].r=a[0].sum=0;
        }
        void insert(int k,int l,int r,int &rt){
            a[size]=a[rt];rt=size++;
            a[rt].sum++;
            if(l==r)return;
            int mid=l+r>>1;
            if(k<=mid)insert(k,l,mid,a[rt].l);
            else insert(k,mid+1,r,a[rt].r);
        }
        int query(int i,int j,int l,int r,int k){
            if(r==k)return a[j].sum-a[i].sum;
            int mid=l+r>>1,t=a[a[j].l].sum-a[a[i].l].sum;
            if(k<=mid)return query(a[i].l,a[j].l,l,mid,k);
            else return t+query(a[i].r,a[j].r,mid+1,r,k);
        }
    }
    void work(){
        int l,r,last=0;
        while(q--){
            l=read();r=read();
            if(k){l^=last;r^=last;}
            last=n-CT::query(root[l-1],root[r],0,m,l-1);
            printf("%d
    ",last);
        }
    }
    void init(){
        int x,y;
        n=read();m=read();q=read();k=read();
        val[0]=MAX;
        for(int i=1;i<=n;i++){
            val[i]=MAX;
            LCT::a[i].v=i;
        }
        for(int i=1;i<=m;i++){a[i].x=read();a[i].y=read();}
        for(int i=1;i<=m;i++){
            x=a[i].x;y=a[i].y;
            if(x==y){
                add_time[i]=i;
                continue;
            }
            if(LCT::find(x)==LCT::find(y)){
                int id=LCT::query(x,y),w=val[id];
                add_time[i]=w;
                LCT::cut(a[w].x,id);
                LCT::cut(a[w].y,id);
            }
            val[i+n]=i;
            LCT::a[i+n].v=i+n;
            LCT::link(x,i+n);
            LCT::link(y,i+n);
        }
        CT::buildtree();
        for(int i=1;i<=m;i++){
            root[i]=root[i-1];
            CT::insert(add_time[i],0,m,root[i]);
        }
    }
    int main(){
        init();
        work();
        return 0;
    }
    
  • 相关阅读:
    数据结构八树和森林
    数据结构 七 二叉树的遍历
    python 的 encode 、decode、字节串、字符串
    TCP/IP
    pg 数据库操作
    nginx + lua 的 跳转命令
    lua string 下的函数
    lua 的匹配规则
    nginx的 ngx.var ngx.ctx ngx.req
    docker 网络模式 和 端口映射
  • 原文地址:https://www.cnblogs.com/Yangrui-Blog/p/9373813.html
Copyright © 2011-2022 走看看