poj 2761 Feed the dogs 平衡树,线段树,树状数组

来源:互联网 发布:物联网如何传输数据 编辑:程序博客网 时间:2024/06/05 06:41

分析:这题就是求区间第k小数,但是这题和poj2104的区别就是,2104的区间是可以完全包含的,就是说某个点进出区间不止一次,所以平衡树和线段树是超时的,只能用划分树或者归并树,这题是可以用平衡树解的。先把区间从左到右排序,然后依次插入平衡树,线段树,然后利用树的性质在log n 内找到第k小。这题也可以用树状数组解,但是需要二分第k小,我一直觉得二分不是最好的做法,考虑能不能在log n内用树状数组找到第k小,一直做不到,所以这题没用树状数组写。

再说一下,平衡树中,treap最好写,sbt据说最快,而且附加域是有用的,是树的节点个数size,而伸展树很灵活可以快速合并分裂翻转,可以实现其他平衡树做不到的。

个人认为,必须要学会伸展树,然后SBT和treap一定要会一种。我学的是SBT。

然后,线段树需要先对数据二分+离散化,因为可能出现很大的值,很浪费内存。

因为要对区间排序,所以要保存区间的顺序下标,最后输出答案有两种方法,一种是获得解后重新按照区间出现顺序排序,第二种是直接ans[interval[i].index]=interval[i].k;

下面是三种不同的解法,线段树,SBT,伸展树。

最后,因为这一题开始只用了线段树写的,后面两种写法是后来学平衡树的时候写的,所以在判断区间重叠的时候不一样。后面多考虑了区间完全重叠的情况,这个数据是没有的,只是为了对拍数据用的。可以删掉。

线段树:

#include<cstdio>#include<cstring>#include<algorithm>using namespace std;#define N 100005#define M 50005int n,m;int pretty[N];int dog[N];struct inter{    int l,r,k;    int ans;    int index;}interval[M];struct tree{    int l,r,p;}tree[N<<2];int binary(int key){    int l=1,r=n;    while(l<=r){        int mid=(l+r)>>1;        if(pretty[mid]==key) return mid;        else if(key<pretty[mid]) r=mid-1;        else l=mid+1;    }}void build(int rt,int l,int r){    tree[rt].l=l;tree[rt].r=r;    if(l<r){        int mid=(l+r)>>1;        build(rt<<1,l,mid);        build(rt<<1|1,mid+1,r);    }}void insert(int rt,int i,int d){    tree[rt].p+=d;    if(tree[rt].l!=tree[rt].r){        int mid=(tree[rt].l+tree[rt].r)>>1;        if(mid>=i) insert(rt<<1,i,d);        else insert(rt<<1|1,i,d);    }}inline bool cmp(const inter &a, const inter &b){    return a.l<b.l||(a.l==b.l&&a.r<b.r);}inline bool operator<(const inter &a, const inter &b){    return a.index<b.index;}int query(int rt,int k){    if(tree[rt].l==tree[rt].r) return pretty[tree[rt].l];    if(tree[rt<<1].p>=k) return query(rt<<1,k);    else return query(rt<<1|1,k-tree[rt<<1].p);}int main(){    memset(tree,0,sizeof(tree));    scanf("%d%d",&n,&m);    for(int i=1; i<=n; i++){        scanf("%d",pretty+i);        dog[i]=pretty[i];    }    for(int i=1;i<=m;i++){        scanf("%d%d%d",&interval[i].l,&interval[i].r,&interval[i].k);        interval[i].index=i;    }    sort(pretty+1,pretty+n+1);    sort(interval+1,interval+m+1,cmp);    for(int i=1;i<=n;i++)        dog[i]=binary(dog[i]);    build(1,1,n);    for(int i=interval[1].l;i<=interval[1].r;i++)        insert(1,dog[i],1);    interval[1].ans=query(1,interval[1].k);    for(int i=2;i<=m;i++){        if(interval[i].l<=interval[i-1].r){            for(int j=interval[i-1].l;j<interval[i].l;j++)                insert(1,dog[j],-1);            for(int j=interval[i-1].r+1;j<=interval[i].r;j++)                insert(1,dog[j],1);        }else{            for(int j=interval[i-1].l;j<=interval[i-1].r;j++)                insert(1,dog[j],-1);            for(int j=interval[i].l;j<=interval[i].r;j++)                insert(1,dog[j],1);        }        interval[i].ans=query(1,interval[i].k);    }    sort(interval+1,interval+m+1);    for(int i=1;i<=m;i++)        printf("%d\n",interval[i].ans);    return 0;}

SBT:

#include<cstdio>#include<algorithm>const int maxn = 100009;const int maxm = 50009;struct cnode{cnode *lchild,*rchild;int s,key;}node[maxn];int sz=1;inline cnode *newnode(cnode*l,cnode*r,int s,int key){node[sz].lchild=l;node[sz].rchild=r;node[sz].s=s;node[sz].key=key;return node+sz++;}struct SBT{cnode *root;cnode *null;SBT(){root=null=node;node[0].s=0;node[0].key=-1;null->lchild=null->rchild=null;}~SBT(){root=null=NULL;}void rotate_r(cnode*&t){cnode *temp=t->lchild;t->lchild=temp->rchild;temp->rchild=t;temp->s=t->s;t->s=t->lchild->s+t->rchild->s+1;t=temp;}void rotate_l(cnode*&t){cnode *temp=t->rchild;t->rchild=temp->lchild;temp->lchild=t;temp->s=t->s;t->s=t->lchild->s+t->rchild->s+1;t=temp;}void maintain(cnode*&t,bool type){if(t==null)return;if(!type){if(t->lchild->lchild->s > t->rchild->s){rotate_r(t);}else if(t->lchild->rchild->s > t->rchild->s){rotate_l(t->lchild);rotate_r(t);}else return;}else{if(t->rchild->rchild->s > t->lchild->s){rotate_l(t);}else if(t->rchild->lchild->s > t->lchild->s){rotate_r(t->rchild);rotate_l(t);}else return;}maintain(t->lchild,false); maintain(t->rchild,true);maintain(t,false);maintain(t,true);}void insert(cnode*&t,int key){if(t==null){t=newnode(null,null,1,key);return;}t->s++;if(key < t->key) insert(t->lchild,key);else insert(t->rchild,key);maintain(t,key>=root->key);}void erase(cnode*&t,int key){if(t==null) return;t->s--;if(t->key==key){if(t->lchild!=null&&t->rchild==null){t=t->lchild;}else if( t->lchild==null && t->rchild==null){t=null;}else{cnode*temp=t->rchild;while(temp->lchild!=null){temp=temp->lchild;}t->key=temp->key;erase(t->rchild,temp->key);}}else if(key<t->key){erase(t->lchild,key);}else{erase(t->rchild,key);}}int kth(int k){//printf("s: %d",root->s);//travel();cnode *t=root;while(1){if(t->lchild->s==k-1)return t->key;else if(t->lchild->s > k-1){t=t->lchild;}else{k-=1+t->lchild->s;t=t->rchild;}}}void erase(int key){erase(root,key);}void insert(int key){insert(root,key);}void travel(){travel(root);}void travel(cnode *t){if(t!=null){travel(t->lchild);printf("%d %d\n",t->s,t->key);travel(t->rchild);}}};SBT tree;struct A{int l,r,k,i;}interval[maxn];int a[maxn];bool cmp2(const A&a,const A&b){return a.l<b.l||a.l==b.l&&a.r<b.r;}bool cmp(const A&a,const A&b){return a.i<b.i;}int main(){int m,n;scanf("%d%d",&n,&m);for(int i=1;i<=n;i++){scanf("%d",a+i);}for(int i=0;i<m;i++){scanf("%d %d %d",&interval[i].l,&interval[i].r,&interval[i].k);interval[i].i=i;}std::sort(interval,interval+m,cmp2);int r=interval[0].r,l=interval[0].l;for(int i=l;i<=r;i++) tree.insert(a[i]);interval[0].k=tree.kth(interval[0].k);for(int i=1;i<m;i++){int R=interval[i].r,L=interval[i].l;if(L>r){while(l<=r){tree.erase(a[l++]);}l=L;r=R;while(L<=R){tree.insert(a[L++]);}}else if(R>r){while(l<L){tree.erase(a[l++]);}while(++r<=R){tree.insert(a[r]);}--r;}else{while(l<L){tree.erase(a[l++]);}while(r>R){tree.erase(a[r--]);}}interval[i].k=tree.kth(interval[i].k);}std::sort(interval,interval+m,cmp);for(int i=0;i<m;i++)printf("%d\n",interval[i].k);return 0;}
Splay:

#include<cstdio>#include<algorithm>const int INF = (unsigned(~0))>>1;const int maxm = 50009;const int maxn = 100009;struct splaytree{    int sz;    struct node{        int s,v;        node *parent;        node *child[2];    };    node pool[maxn];    node* null;    node* root;    node nil;    splaytree(){        root=null=&nil;        nil.parent=nil.child[0]=nil.child[1]=null;        sz=nil.v=nil.s=0;        insert(-INF);        insert(INF);    }    node* newnode(node*p,int key){        pool[sz].parent=p;        pool[sz].child[0]=pool[sz].child[1]=null;        pool[sz].s=1;        pool[sz].v=key;        return pool+sz++;    }    void update(node* x){        if(x != null){            x->s = x->child[0]->s + x->child[1]->s + 1;        }    }    void insert(int key){        if(root==null){            root=newnode(null,key);        }else{            node *t=root;            while(true){                int d=t->v < key;                t->s++;                if(t->child[d]==null){                    t->child[d] = newnode(t,key);                    splay(t->child[d],null);                    return;                }else{                    t=t->child[d];                }            }        }    }    void remove(int value){        int k=find(value);        findkth(k-1,null);        findkth(k+1,root);        root->s--;        root->child[1]->s--;        root->child[1]->child[0]=null;    }    void rotate(node *x,int dr){        node *p = x->parent;        x->child[dr]->parent=p;        p->child[1^dr] = x->child[dr];        x->parent=p->parent;        x->child[dr]=p;        if(p->parent->child[0]==p){            p->parent->child[0]=x;        }else if(p->parent->child[1]==p){            p->parent->child[1]=x;        }else   root=x;        p->parent=x;        update(p);        update(x);    }    void splay(node *x, node *y){        while(x->parent != y){            if(x->parent->parent==y){                if(x->parent->child[0]==x)rotate(x,1);                else rotate(x,0);            }else if(x->parent->parent->child[0] == x->parent){                if(x->parent->child[0]==x){                    rotate(x->parent,1);                    rotate(x,1);                }else{                    rotate(x,0);                    rotate(x,1);                }            }else{                if(x->parent->child[1]==x){                    rotate(x->parent,0);                    rotate(x,0);                }else{                    rotate(x,1);                    rotate(x,0);                }            }        }    }    int find(int key){        node *t=root;        int sum=0;        while(true){            if(t->v == key){                return sum + t->child[0]->s + 1;            }else if(t->v > key){                t = t->child[0];            }else{                sum += t->child[0]->s + 1;                t = t->child[1];            }        }    }    int getkth(int k){        findkth(k+1,null);        return root->v;    }    void findkth(int k,node *y){        node *x = root;        while(k != x->child[0]->s + 1){            if(k < x->child[0]->s + 1 ){                x = x->child[0];            }else{                k -= x->child[0]->s + 1;                x = x->child[1];            }        }        splay(x,y);    }};splaytree tree;struct A{int l,r,i,k;}interval[maxn];int a[maxn];int ans[maxm];bool operator<(const A&a,const A&b){return a.l<b.l||a.l==b.l&&a.r<b.r;}int main(){    int m,n;scanf("%d%d",&n,&m);        for(int i=1;i<=n;i++){            scanf("%d",a+i);        }        for(int i=0;i<m;i++){scanf("%d %d %d",&interval[i].l,&interval[i].r,&interval[i].k);interval[i].i=i;}        std::sort(interval,interval+m);        int r=interval[0].r,l=interval[0].l;        for(int i=l;i<=r;i++) tree.insert(a[i]);        ans[interval[0].i]=tree.getkth(interval[0].k);        for(int i=1;i<m;i++){            int R=interval[i].r,L=interval[i].l;            if(L>r){                while(l<=r){                    tree.remove(a[l++]);                }                l=L;r=R;                while(L<=R){                    tree.insert(a[L++]);                }            }else if(R>r){                while(l<L){                    tree.remove(a[l++]);                }                while(++r<=R){                    tree.insert(a[r]);                }                --r;            }            else{                while(l<L){                    tree.remove(a[l++]);                }                while(r>R){                    tree.remove(a[r--]);                }            }            ans[interval[i].i]=tree.getkth(interval[i].k);        }        for(int i=0;i<m;i++)            printf("%d\n",ans[i]);    return 0;}


原创粉丝点击