bzoj3514

对于这道题,想都没想,毫不犹豫的看了题解,这样就变成了只是练习写代码,没有思考。觉得自己这样不好。必须改。

参考题解:

http://wenku.baidu.com/view/a611cec4dd3383c4bb4cd2d8.html

http://blog.csdn.net/jiangyuze831/article/details/41694643

简单证明:

求(L,R)的联通块个数,是相当于往一个只有点1到n的,没有边的图中添加边(L,R),假设边X ,L<=X<=R,X添加后,可能会少一个联通块,也可能不回少,在于它所连接的那两个点是不是已经是联通的,但是这个联通是要求用(L,X-1)这些边造成的联通,所以要始终维护一棵树,(维护一棵树的意义就是,不连通的两个点因为加入某条边Y联通后,就一直处于联通装态,不会断开,同时维护最大生成树(每条边的编号是它的权值),使得树又是用离Y最近的边构成的),因此,在加入X时,X连接的两个点,有三种情况:

1.两点不连通,既然(1,X-1)都无法是这两个点联通,那么(L,X-1)也无法是这两个点联通。加入X后,会使得联通块个数减少1。

2.两点联通,且两点之间路径上的最小值小于L。如果存在(L,X-1)使得这两个点联通的话,那么此时最小值就一定大于等于L,(L,X-1)无法使得这两个点联通。加入X后,会联通块个数减少1。

3.两点联通,且两点之间路径上的最大值大于等于L,说明(L,X-1)可以使得这两个点联通,加入X后,不会使得联通块个数减少.

4.X链接的两点相同,那么此时联通块个数不会减少。

综上所述,用lct维护一棵最大生成树,数组num[i] 记载,加入某条边 i 时,两点不连通,则num[i]=0,如果两点联通,则记录路径上最小权值,特别的,如果一条边的两点相同时,num[i]=n+1(n是边的个数)。

代码:

#include<stdio.h>
#include<string.h>
#include<iostream>
using namespace std;
#define N 200010
#define INF 0x3f3f3f3f

struct node{
    node *fa;
    node *ch[2];
    int rev;
    int val;
    int minval;
    int valnum;
    int minvalnum;//用来记录以某个点为根节点的子树的最大值,而不是左子树的最大值,否则可能会错(不知道有没有严格的证明来证明绝对不会出错?所以这里只写可能会出错)
    int from;//涉及到维护生成树时,要有from和to
    int to;

    int init(int tempval,int tempvalnum,int tempfrom,int tempto){
        ch[0]=ch[1]=fa=NULL;
        rev=0;
        val=tempval;
        minval=val;
        valnum=tempvalnum;
        minvalnum=valnum;
        from=tempfrom;
        to=tempto;
    }

    bool isroot(){
        /*if(this==NULL){//这个输出了
            printf("hahaha\n");
        }*/
        return fa==NULL||(fa->ch[0]!=this&&fa->ch[1]!=this);
    }

    void fswitch(){
        rev^=1;
        swap(ch[0],ch[1]);
    }

    void push_down(){
        if(rev){
            if(ch[0]){
                ch[0]->fswitch();
            }
            if(ch[1]){
                ch[1]->fswitch();
            }
            rev=0;
        }

        return;
    }

    void go(){
        /*if(this==NULL){//这里输出了
            printf("wo shi da hao ren");
        }*/
        if(!isroot()){
            fa->go();
        }
        push_down();

        return;
    }

    int dir(){
        return fa->ch[1]==this?1:0;
    }

    void setedge(int d,node *another){
        ch[d]=another;
        if(another){
            another->fa=this;//这里是this,不是NULL
        }

        return;
    }

    void push_up(){
        minvalnum=valnum;
        minval=val;

        if(ch[0]){
            if(minvalnum>ch[0]->minvalnum){
                minval=ch[0]->minval;
                minvalnum=ch[0]->minvalnum;
            }
        }
        if(ch[1]){
            if(minvalnum>ch[1]->minvalnum){
                minval=ch[1]->minval;
                minvalnum=ch[1]->minvalnum;
            }
        }

        return;
    }

    void rot(){
        int d=dir();
        node *tempfafa=fa->fa;
        if(!(fa->isroot())){
            tempfafa->ch[fa->dir()]=this;
        }
        fa->setedge(d,ch[!d]);
        setedge(!d,fa);
        fa=tempfafa;
        ch[!d]->push_up();

        return;
    }

    void splay(){
        /*if(this==NULL){
            printf("wo shi da hao ren");//这里输出了
        }*/
        go();

        while(!isroot()){
            if(!(fa->isroot())){
                dir()==fa->dir()?fa->rot():rot();
            }
            rot();
        }
        push_up();

        return;
    }

    void access(){
        for(node *p=this,*q=NULL;p!=NULL;q=p,p=p->fa){
            p->splay();
            p->setedge(1,q);
            p->push_up();
        }
        /*if(this==NULL){
            printf("wo shi da hao ren");//这里输出了
        }*/
        splay();

        return;
    }

    void make_root(){
        /*if(this==NULL){//这里输出了
            printf("wo sh da hao ren");
        }*/
        access();
        fswitch();
    }

    void cut(node *another){
        /*if(another==NULL){//这里输出了
            printf("wo shi da hao ren");
        }*/
        another->make_root();
        access();
        ch[0]->fa=NULL;
        ch[0]=NULL;
        push_up();

        return;
    }

    void link(node *another){
        another->make_root();
        another->fa=this;

        return;
    }

    node *find_root(){
        node *temp=this;

        while(temp->fa){//这里出现了死循环,说明某个temp->fa==temp,应该是前面lct的基本操作出了问题
            /*if(temp==temp->fa){
                printf("wo shi da hao ren");
            }*/
            temp=temp->fa;
        }

        return temp;
    }

    bool islink(node *another){
        return find_root()==another->find_root()?true:false;
    }

    int query(node *another){
        another->make_root();
        access();
        return minval;
    }
};

node *tree[2*N],pool[2*N];
int num[N];
int Tree[N];
int c[30*N],lson[30*N],rson[30*N];
int cou;//记得初始化
int m;

void addedge(int x,int y,int id){
    if(x==y){
        num[id]=m+1;//注意这里的return必须添加
        return;
    }
    if(tree[x]->islink(tree[y])){
        int tempval=tree[x]->query(tree[y]);
        if(tree[tempval]->valnum<id){
            num[id]=tree[tempval]->valnum;
            tree[tempval]->cut(tree[tree[tempval]->from]);
            tree[tempval]->cut(tree[tree[tempval]->to]);
            tree[tempval]->init(tempval,id,x,y);
            tree[tempval]->link(tree[x]);
            tree[tempval]->link(tree[y]);
        }
    }
    else{
        tree[++cou]=&(pool[cou]);
        tree[cou]->init(cou,id,x,y);

        tree[cou]->link(tree[x]);
        tree[cou]->link(tree[y]);
        num[id]=0;
    }

    return;
}

int build(int l,int r){
    int root=cou++;

    c[root]=0;
    if(l!=r){
        int middle=(l+r)>>1;

        lson[root]=build(l,middle);
        rson[root]=build(middle+1,r);
    }

    return root;
}

int insert(int froroot,int x){
    int root=cou++,temproot=root;
    int l=0,r=m+1;

    c[temproot]=c[froroot]+1;
    while(l<r){
        int middle=(l+r)>>1;

        if(x<=middle){
            r=middle;
            lson[temproot]=cou++;
            rson[temproot]=rson[froroot];
            temproot=lson[temproot];
            froroot=lson[froroot];
        }
        else{
            l=middle+1;
            lson[temproot]=lson[froroot];
            rson[temproot]=cou++;
            temproot=rson[temproot];
            froroot=rson[froroot];
        }
        c[temproot]=c[froroot]+1;
    }

    return root;
}

int query(int root,int l,int r,int x){
    if(l==r){
        if(l<x){
            return c[root];
        }
        else{
            return 0;
        }
    }
    else{
        int middle=(l+r)>>1;

        if(x<=middle){
            return query(lson[root],l,middle,x);
        }
        else{
            return c[lson[root]]+query(rson[root],middle+1,r,x);
        }
    }
}

int main(){
    int n,k,type;
    int a,b;

    scanf("%d%d%d%d",&n,&m,&k,&type);
    for(int i=1;i<=n;i++){
        tree[i]=&(pool[i]);
        tree[i]->init(i,INF,-1,-1);
    }
    cou=n;//这个要放对位置,否则会re
    for(int i=1;i<=m;i++){
        scanf("%d%d",&a,&b);
        addedge(a,b,i);
    }

    Tree[0]=build(0,m+1);
    for(int i=1;i<=m;i++){
        Tree[i]=insert(Tree[i-1],num[i]);
    }

    if(type){
        int lastans=0;
        for(int i=0;i<k;i++){
            scanf("%d%d",&a,&b);
            a=a^lastans;
            b=b^lastans;
            lastans=n-query(Tree[b],0,m+1,a)+query(Tree[a-1],0,m+1,a);
            printf("%d\n",lastans);
        }
    }
    else{
        for(int i=0;i<k;i++){
            scanf("%d%d",&a,&b);
            printf("%d\n",n-query(Tree[b],0,m+1,a)+query(Tree[a-1],0,m+1,a));
        }
    }

    return 0;
}


posted @ 2015-09-05 10:46  buzhidaohahaha  阅读(176)  评论(0编辑  收藏  举报