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\n",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;
}

 

posted @ 2018-07-26 19:19  符拉迪沃斯托克  阅读(172)  评论(0编辑  收藏  举报
Live2D