hdu 4680 splay,启发式合并

hdu 4680 splay,启发式合并

这个题是按照权值建树,一般的区间树操作可能得修改一下。
几个操作也很有想法:
1.合并两个集合。这里用到启发式合并的方式,也就是把小的集合一个个插到大的上,
可以证明合并操作不会超过O(nlogn)级别次。
2.拔、插。这是splay的基础不用说了。
3.改。因为是权值建树,不能直接改。先拔出来改了再插回去。
4.这个很巧妙,取最多的点最优的方式肯定是从小到大取,后一个要大于前两个的和。
这样取的数值会增加一倍,这样不超过logn次,暴力搞即可。

5.区间的gcd。也是splay的基础操作。把区间转到一个子树上,求根的值即可。

所以总的就是O(nlognlogn)


#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
#define NN 310010

const int inf=2000001000;

int getgcd(int a,int b){
    int t;
    while(b){t=a;a=b;b=t%b;}
    return a;
}

struct sn{
    sn *c[2],*f;
    int val;
    int size;
    int gcd;
    int r;

    inline void init(){
        f=c[0]=c[1]=NULL;
        gcd=val=0;
        r=0;
        size=1;
    }
    inline void setval(int b){val=gcd=b;}
    inline void rot(int d){
        sn *y=f,*z=y->f;
        y->c[!d]=c[d]; if(c[d]) c[d]->f=y;
        f=z; if(z) if(y==z->c[0]) z->c[0]=this; else z->c[1]=this;
        c[d]=y; y->f=this;
        y->update();
    }
    inline void splay(sn *fa){
        while(f != fa){
            if(f->f == fa) {
                if( f->c[0] == this) rot(1);
                else rot(0);
            }else{
                sn *y=f,*z=y->f;
                if( y->c[0] == this){
                    if( z->c[0]==y ) { y->rot(1); rot(1); }
                    else{ rot(1); rot(0); }
                }else{
                    if( z->c[0]!=y ) { y->rot(0); rot(0); }
                    else{ rot(0); rot(1); }
                }
            }
        }
        update();
    }
    inline void update(){
        size=1;
        if (c[0]) size+=c[0]->size;
        if (c[1]) size+=c[1]->size;
        gcd=val;
        if (c[0]) gcd=getgcd(gcd,c[0]->gcd);
        if (c[1]) gcd=getgcd(gcd,c[1]->gcd);
    }
    inline sn* select(int r){ //按左右序第r个
        //push_down();
        int cnt=0; if( c[0] ) cnt+=c[0]->size;
        if( r<=cnt ) return c[0]->select(r);
        if( r==cnt+1) return this;
        return c[1]->select(r-cnt-1);
    }

}tp[NN],*root[NN];
int tn; //初始化

sn* _alloc() { tp[++tn].init(); return &tp[tn];}

sn* lower_bound(sn *root,int val){ //first >=val
    sn *ret=NULL,*p=root;
    while(p){
        if (val<=p->val&&(!ret||p->val<=ret->val)){
            ret=p;
        }
        if (p->val>=val) p=p->c[0];
        else p=p->c[1];
    }
    return ret;
}

sn* upper_bound(sn *root,int val){  // first >val
    sn *ret=NULL,*p=root;
    while(p){
        if (val<p->val&&(!ret||p->val<=ret->val)){
            ret=p;
        }
        if (p->val>val) p=p->c[0];
        else p=p->c[1];
    }
    return ret;
}

sn* lower_bound_r(sn *root,int val){   //last <=val
    sn *ret=NULL,*p=root;
    while(p){
        if (val>=p->val&&(!ret||p->val>=ret->val)){
            ret=p;
        }
        if (p->val<=val) p=p->c[0];
        else p=p->c[1];
    }
    return ret;
}

sn* upper_bound_r(sn *root,int val){   //last <val
    sn *ret=NULL,*p=root;
    while(p){
        if (p->val<val&&(!ret||p->val>=ret->val)){
            ret=p;
        }
        if (p->val<val) p=p->c[1];
        else p=p->c[0];
    }
    return ret;
}
//--------------------------------------------------------
void insert(sn *now,int y){
    sn *p=root[y];
    sn *t1=upper_bound_r(p,now->val);
    sn *t2=lower_bound(p,now->val);
    t1->splay(NULL);
    t2->splay(t1);
    t2->c[0]=now;
    now->f=t2;
    now->r=y;
    now->splay(NULL);root[y]=now;
}

void del(sn *p,int x){
    p->splay(NULL);
    sn* tmp=p->c[1]->select(1);
    tmp->splay(p);
    tmp->c[0]=p->c[0];p->c[0]->f=tmp;
    p->c[0]=p->c[1]=p->f=NULL;
    tmp->f=NULL;
    tmp->splay(NULL); root[x]=tmp;
}

void dfs(sn *p,int y){
    if (p->c[0]) {dfs(p->c[0],y);p->c[0]=NULL;}
    if (p->c[1]) {dfs(p->c[1],y);p->c[1]=NULL;}
    p->f=NULL;
    if (p->val==0||p->val==inf) return;
    insert(p,y);
}

int query1(int x){
    sn *p=root[x],*p1,*p2;
    if (root[x]->size<=4) return root[x]->size-2;
    p1=lower_bound(p,1);
    p2=upper_bound_r(p,p1->val+1);
    int now,last,ret;
    if (p1!=p2){
        now=p2->val;
        last=p1->val;
        ret=2;
    }
    else {
        now=p2->val;
        last=1;
        ret=1;
    }
    while(1){
        if (now==inf) break;
        p1=lower_bound(p,now+last);
        ret++;
        last=now;
        now=p1->val;
    }
    return ret-1;
}

int query2(int x,int l,int r){
    sn *p=root[x],*p1,*p2;
    p2=upper_bound(p,r);
    p1=upper_bound_r(p,l);
    p1->splay(NULL);root[x]=p1;
    p2->splay(p1);
    if (!p2->c[0]) return -1;
    else return p2->c[0]->gcd;
}

int h[NN/3];
sn* ptr[NN/3];

void init_splay(int n){
    tn=-1;
    int i;
    sn *p;
    for(i=1;i<=n;++i){
        ptr[i]=_alloc();
        ptr[i]->setval(h[i]);
        ptr[i]->r=i;
        root[i]=ptr[i];
        p=_alloc();
        p->setval(0);
        ptr[i]->c[0]=p;p->f=ptr[i];
        p=_alloc();
        p->setval(inf);
        ptr[i]->c[1]=p;p->f=ptr[i];
        ptr[i]->update();
    }
}

int main(){
    //freopen("4680in.txt","r",stdin);
    int tcas,cas;
    int i,m,n;
    int a,b,c,f,x,y;
    int t1,t2;
    sn *tmp,*tt,*tt2;

    char s[20];
    scanf("%d",&tcas);
    for(cas=1;cas<=tcas;++cas){
        scanf("%d%d",&n,&m);
        for(i=1;i<=n;++i){
            scanf("%d",&h[i]);
        }
        init_splay(n);
        printf("Case #%d:\n",cas);
        for(i=1;i<=m;++i){
            scanf("%d",&f);
            if (f==1){
                scanf("%d%d",&a,&b);
                x=ptr[a]->r;y=ptr[b]->r;
                if (x==y) continue;
                if (root[x]->size>root[y]->size){
                    swap(x,y);
                    swap(a,b);
                }
                dfs(root[x],y);
            }
            else if(f==2){
                scanf("%d%d",&a,&b);
                x=ptr[a]->r;y=ptr[b]->r;
                del(ptr[a],x);
                insert(ptr[a],y);
                ptr[a]->r=y;
            }
            else if(f==3){
                scanf("%d%d",&a,&b);
                x=ptr[a]->r;
                del(ptr[a],x);
                ptr[a]->setval(b);
                insert(ptr[a],x);
            }
            else if(f==4){
                scanf("%d",&a);
                x=ptr[a]->r;
                printf("%d\n",query1(x));
            }
            else if (f==5){
                scanf("%d%d%d",&a,&b,&c);
                x=ptr[a]->r;
                printf("%d\n",query2(x,b,c));
            }
        }
    }
    return 0;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值