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;
    }
    
  • 相关阅读:
    hdu 6702 ^&^ 位运算
    hdu 6709 Fishing Master 贪心
    hdu 6704 K-th occurrence 二分 ST表 后缀数组 主席树
    hdu 1423 Greatest Common Increasing Subsequence 最长公共上升子序列 LCIS
    hdu 5909 Tree Cutting FWT
    luogu P1588 丢失的牛 宽搜
    luogu P1003 铺地毯
    luogu P1104 生日
    luogu P1094 纪念品分组
    luogu P1093 奖学金
  • 原文地址:https://www.cnblogs.com/Yangrui-Blog/p/9373813.html
Copyright © 2011-2022 走看看