BZOJ 3514: Codechef MARCH14 GERALD07加强版 [LCT 主席树 kruskal]

3514: Codechef MARCH14 GERALD07加强版

Time Limit: 60 Sec  Memory Limit: 256 MB
Submit: 1312  Solved: 501
[Submit][Status][Discuss]

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

Source

By zhonghaoxi


 

刚刚去看了CreationAugust的Blog,感觉好伤感,也许我的未来就是这样吧

 

这道题好神啊

 

LCT维护动态最小生成树,先将每条边依次加进去,若形成环弹掉最早加进去的边,然后记录early[]数组,表示第i条边弹掉了哪条边,若没有弹出边,early[i]=0
然后每个询问的答案就是用n减掉[l,r]区间内ntr值小于l的边的数量 可以用主席树来维护
注意有自环

early[i]数组记录的边不算的话i就可以贡献一个连通分量了,所以这样做

又调了好长时间,最后发现主席树挂掉了因为以前写顺手了虽然是mid=(l+r)>>1但还是用了m...............RE一片

 

最后说一下一道题用了多个大数据结构怎么办:

1.可以用namespace

2.宏定义是可以取消的,#undef 名字

 

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
using namespace std;
#define pa t[x].fa
#define lc t[x].ch[0]
#define rc t[x].ch[1]
const int N=2e5+5;
typedef long long ll;
inline int read(){
    char c=getchar();int x=0,f=1;
    while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();}
    while(c>='0'&&c<='9'){x=x*10+c-'0';c=getchar();}
    return x*f;
}

int n,m,Q,type;
struct LCTnode{
    int ch[2],fa,rev,w,mx,p;
}t[N<<1];
inline int wh(int x){return t[pa].ch[1]==x;}
inline int isRoot(int x){return t[pa].ch[0]!=x&&t[pa].ch[1]!=x;}
inline void update(int x){
    t[x].mx=t[x].w;t[x].p=x;
    if(t[lc].mx>t[x].mx) t[x].mx=t[lc].mx,t[x].p=t[lc].p;
    if(t[rc].mx>t[x].mx) t[x].mx=t[rc].mx,t[x].p=t[rc].p;
}
inline void rever(int x){
    t[x].rev^=1;
    swap(lc,rc);
}
inline void pushDown(int x){
    if(t[x].rev){
        rever(lc);
        rever(rc);
        t[x].rev=0;    
    }
}
inline void rotate(int x){
    int f=t[x].fa,g=t[f].fa,c=wh(x);
    if(!isRoot(f)) t[g].ch[wh(f)]=x;t[x].fa=g;
    t[f].ch[c]=t[x].ch[c^1];t[t[f].ch[c]].fa=f;
    t[x].ch[c^1]=f;t[f].fa=x;
    update(f);update(x);
}
int st[N],top;
inline void splay(int x){
    top=0;st[++top]=x;
    for(int i=x;!isRoot(i);i=t[i].fa) st[++top]=t[i].fa;
    for(int i=top;i>=1;i--) pushDown(st[i]);
    
    for(;!isRoot(x);rotate(x))
        if(!isRoot(pa)) rotate(wh(x)==wh(pa)?pa:x);
}
inline void Access(int x){
    for(int y=0;x;y=x,x=pa){
        splay(x);
        rc=y;
        update(x);
    }
}
inline void MakeR(int x){
    Access(x);splay(x);
    rever(x);
}
inline int FindR(int x){
    Access(x);splay(x);
    while(lc) x=lc;
    return x;
}
inline void Link(int x,int y){
    MakeR(x);
    t[x].fa=y;
}
inline void Cut(int x,int y){
    MakeR(x);Access(y);splay(y);
    t[y].ch[0]=t[x].fa=0;
    update(y);//!!!
}
inline void Split(int x,int y){
    MakeR(x);Access(y);splay(y);
}
inline int Que(int x,int y){
    MakeR(x);Access(y);splay(y);
    return t[y].p;
}

struct edge{
    int u,v;
}e[N];
int early[N];
void Kruskal(){
    for(int i=1;i<=m;i++){//printf("kru %d\n",i);
        int u=e[i].u,v=e[i].v;
        if(u==v) {early[i]=i;continue;}
        if(FindR(u)==FindR(v)){
            int p=Que(u,v);
            early[i]=p-n;
            Cut(e[p-n].u,p);Cut(e[p-n].v,p);
        }
        Link(u,i+n);Link(v,i+n);
    }
}

#undef lc
#undef rc
#define lc(x) t[x].l
#define rc(x) t[x].r
namespace F{
    struct Fnode{
        int l,r,size;
    }t[N*30];
    int sz=0,root[N];
    void ins(int &x,int l,int r,int p){
        t[++sz]=t[x]; x=sz;
        t[x].size++;
        if(l==r) return;
        int mid=(l+r)>>1;
        if(p<=mid) ins(t[x].l,l,mid,p);
        else ins(t[x].r,mid+1,r,p);
    }
    int que(int x,int y,int l,int r,int ql,int qr){//printf("que %d %d %d %d\n",l,r,ql,qr);
        if(ql<=l&&r<=qr) return t[y].size-t[x].size;
        else{
            int m=(l+r)>>1,ans=0;
            if(ql<=m) ans+=que(lc(x),lc(y),l,m,ql,qr);
            if(m<qr) ans+=que(rc(x),rc(y),m+1,r,ql,qr);
            return ans;
        }
    }
    int l,r,lastans=0;
    void solve(){
        for(int i=1;i<=m;i++) root[i]=root[i-1],ins(root[i],0,m,early[i]);
        //for(int i=0;i<=m;i++) printf("root %d\n",root[i]); 
        while(Q--){
            l=read();r=read();
            if(type) l^=lastans,r^=lastans;
            lastans=n-que(root[l-1],root[r],0,m,0,l-1);
            printf("%d\n",lastans);
        }
    }
}
int main(){
    //freopen("in.txt","r",stdin);
    n=read();m=read();Q=read();type=read();
    for(int i=1;i<=m;i++){
        e[i].u=read(),e[i].v=read();
        t[i+n].w=t[i+n].mx=m+n-i+1;
        t[i+n].p=i+n;
    }
    Kruskal();
    F::solve();
}

 

 

 

 

 

 

 

 

 

posted @ 2017-01-12 20:52  Candy?  阅读(1294)  评论(0编辑  收藏  举报