HDU 2852 KiKi's K-Number(动态过程求第K小数)

来源:互联网 发布:h3c路由器端口映射 sql 编辑:程序博客网 时间:2024/06/05 17:54
题意:
给出三种操作,
0 在容器中插入一个数。
1 在容器中删除一个数。

2 求出容器中大于a的第k大元素。

思路:可以用树状数组和线段树,显然a[1]+...+a[i]随i有明显的单调性,所以可以二分出答案

线段树时间复杂度比树状数组的常数大了几倍...所以线段树擦边过了

还有另外一种思路:二分只是二分出a[1]+...+a[i]的上界i,所以可以逆向考虑,从a[1]开始累加,直到到达k,这样的复杂度就由原来的

O(lgN*lgN) 变成O(lgN)了。难在累加的过程,线段树和树状数组是同样的累加方法详见代码


线段树二分代码:

129892102015-02-25 20:49:32Accepted28521965MS4176K2321 BC++ka

#include <iostream>#include <cstdio>#include <cstdlib>#include <cstring>#include <algorithm>#include <cmath>using namespace std;const int M = 100010;#define lson l, m, rt<<1#define rson m+1, r, rt<<1|1struct node{    int l,r;    int sum;}tree[M<<2];int ans = 0;void build(int l,int r,int rt)//建树{    tree[rt].l =l;    tree[rt].r =r;    tree[rt].sum =0;    if(l ==r ) return ;    int m=(l+r)>>1;    build(lson);    build(rson);}void up(int rt){    tree[rt].sum=tree[rt<<1].sum+tree[rt<<1|1].sum;}void updata(int l,int r,int rt,int pos,int j){    if(l==r)  {        tree[rt].sum +=j;        return;    }    int m=(tree[rt].l +tree[rt].r )/2;    if(pos<=m)        updata(lson,pos,j);    else        updata(rson,pos,j);    up(rt);}int query(int rt,int L,int R){    int m=(tree[rt].l +tree[rt].r)>>1;    if(L<=tree[rt].l&&tree[rt].r <=R)    {        return tree[rt].sum ;    }    int ans=0;    if(L<=m)        ans+=query(rt<<1,L,R);    if(R>m)        ans+=query(rt<<1|1,L,R);    return ans;}int B_search(int k){    int lb = 1;    int ub = M-1;    int w=-1;    while(lb<=ub)    {        int m = (lb + ub)>>1;        ans=query(1,1,m);        if(ans>=k)        {            ub = m - 1;            w=m;        }        else        {            lb = m+1;        }    }    return w;}int main(){    int n,a,b,k;    while(~scanf("%d",&n))    {        build(1,M,1);        for(int i = 0;i<n;i++)        {            scanf("%d",&a);            if(a==0)            {                scanf("%d",&b);                updata(1,M,1,b,1);            }            else if(a==1)            {                scanf("%d",&b);                ans=query(1,b,b);                if(!ans)                    puts("No Elment!");                else                    updata(1,M,1,b,-1);            }            else if(a==2)            {                scanf("%d%d",&b,&k);                ans=query(1,1,b);                int tmp = B_search(ans+k);                if(tmp==-1)                    puts("Not Find!");                else                    printf("%d\n",tmp);            }        }    }    return 0;}

树状数组二分代码:(可见比线段树快了很多)

//468MS 1484K#include<cstdio>#include<algorithm>#include<cstring>#include<iostream>using namespace std;#define M 100100#define lowbit(x) (x&-x)int m;int C[M];void update(int rt,int val){    for(int i=rt;i<M;i+=lowbit(i)){        C[i]+=val;    }}int sum(int rt){    int s=0;    for(int i=rt;i>0;i-=lowbit(i)){        s+=C[i];    }    return s;}int main(){    while(~scanf("%d",&m)){        int op;        memset(C,0,sizeof(C));        while(m--){            scanf("%d",&op);            if(op==0){                int x;                scanf("%d",&x);                update(x,1);            }            else if(op==1){                int x;                scanf("%d",&x);                if(sum(x)-sum(x-1)==0){                    printf("No Elment!\n");                    continue;                }                update(x,-1);            }            else {                int x,k;                scanf("%d%d",&x,&k);                k+=sum(x);                int lb=1,ub=M-1;                while(ub>=lb){                    int mid=(lb+ub)>>1;                    if(sum(mid)>=k) ub=mid-1;                    else lb=mid+1;                }                if(lb==M) printf("Not Find!\n");                else printf("%d\n",lb);            }        }    }    return 0;}


逆向累加:(树状数组的累加是二进制的操作,可还原树形图来便于理解)

http://www.cnblogs.com/wuyiqi/archive/2011/12/25/2301071.html 这篇文章有解释

这样果然快了不少,跑到第11名11ka312MS1484K1420B 

//312MS 1484K#include<cstdio>#include<algorithm>#include<cstring>#include<iostream>using namespace std;#define M 100100#define lowbit(x) (x&-x)int m;int C[M];void update(int rt,int val){    for(int i=rt;i<M;i+=lowbit(i)){        C[i]+=val;    }}int sum(int rt){    int s=0;    for(int i=rt;i>0;i-=lowbit(i)){        s+=C[i];    }    return s;}int find_kth(int k){    int ans=0,s=0;    for(int i=20;i>=0;i--){        ans+=(1<<i);        if(ans>=M||s+C[ans]>=k){            ans-=(1<<i);        }        else s+=C[ans];    }    return ++ans;}int main(){    while(~scanf("%d",&m)){        int op;        memset(C,0,sizeof(C));        while(m--){            scanf("%d",&op);            if(op==0){                int x;                scanf("%d",&x);                update(x,1);            }            else if(op==1){                int x;                scanf("%d",&x);                if(sum(x)-sum(x-1)==0){                    printf("No Elment!\n");                    continue;                }                update(x,-1);            }            else {                int x,k;                scanf("%d%d",&x,&k);                k+=sum(x);                int ans=find_kth(k);                if(ans==M) printf("Not Find!\n");                else printf("%d\n",ans);            }        }    }    return 0;}


线段树的逆向累加方法也比二分快了不少:

//655MS 2660K#include<cstdio>#include<iostream>#include<cstring>#include<algorithm>using namespace std;#define M 100100#define lson l,m,rt<<1#define rson m+1,r,rt<<1|1int tree[M<<2];bool flag;void up(int rt){    tree[rt]=tree[rt<<1]+tree[rt<<1|1];}bool update(int pos,int val,int l,int r,int rt){    flag=true;    if(l==r){        if(val==-1&&tree[rt]==0){            flag=false;            return false;        }        tree[rt]+=val;        return true;    }    int m=(l+r)>>1;    if(pos<=m) update(pos,val,lson);    else update(pos,val,rson);    up(rt);    return flag? true:false;}int query(int L,int R,int l,int r,int rt){    if(L<=l&&r<=R){        return tree[rt];    }    int m=(l+r)>>1;    int ans=0;    if(L<=m) ans+=query(L,R,lson);    if(R>m) ans+=query(L,R,rson);    return ans;}void find_kth(int l,int r,int rt,int k){    if(l==r)    {        printf("%d\n",l);        return ;    }    int m=(l+r)>>1;    if(k<=tree[rt<<1]) find_kth(lson,k);    else find_kth(rson,k-tree[rt<<1]);}int main(){    int m;    while(~scanf("%d",&m)){        memset(tree,0,sizeof(tree));        while(m--){            int op;            scanf("%d",&op);            if(op==0){                int x;                scanf("%d",&x);                update(x,1,1,M-1,1);            }            else if(op==1){                int x;                scanf("%d",&x);                if(update(x,-1,1,M-1,1)==false) printf("No Elment!\n");            }            else {                int a,k;                scanf("%d%d",&a,&k);                k+=query(1,a,1,M-1,1);                if(k>tree[1]){                    printf("Not Find!\n");                    continue;                }                find_kth(1,M-1,1,k);            }        }    }    return 0;}





0 0
原创粉丝点击