poj 2761 Feed the dogs 求区间第k大的数

此题有一个关键的地方决定了可以使用树状数组来搞:所有询问的区间不相互包含,但可能交叉

这样就可以从左往右边添加边删除用树状数组来做了

如果存在包含关系,就不能用树状数组搞了,原因的话看看poj 2104 的样例数据就明白了

View Code
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int maxn = 100010;
struct node{
    int key,id;
    bool operator < (const node & cm)const{
        return key<cm.key;
    }
}dog[maxn];
struct PP{
    int l,r,kx,id;
    bool operator < (const PP & cm)const {
        if(l!=cm.l)return l<cm.l;
        return r<cm.r;
    }
}q[maxn];
int c[maxn],x[maxn],ran[maxn],ans[maxn];
void update(int x,int d){
    for(;x<maxn;x+=x&-x)
        c[x]+=d;
}
int find_kth(int k){
    int ans = 0, cnt = 0, i;
    for (i = 20; i >= 0; i--){
        ans += (1 << i);
        if (ans >= maxn|| cnt + c[ans] >= k)
            ans -= (1 << i);
        else
            cnt += c[ans];
    }
    return ans + 1;
}
int main(){
    int n,m,i,j,k,a,b;
    scanf("%d%d",&n,&m);
    for(i=1;i<=n;i++){
        scanf("%d",&dog[i].key);
        dog[i].id=i;
    }
    sort(dog+1,dog+1+n);x[1]=dog[1].key;ran[dog[1].id]=1;
    for(j=1,i=2;i<=n;i++){
        if(dog[i].key!=dog[i-1].key) x[++j]=dog[i].key;
        ran[dog[i].id]=j;
    }
    for(i=1;i<=m;i++){
        scanf("%d%d%d",&a,&b,&k);
        if(a>b) swap(a,b);        
        q[i].l=a;q[i].r=b;q[i].kx=k;q[i].id=i;
    }
    q[0].l=1;q[0].r=0;
    sort(q+1,q+m+1);
    for(i=1;i<=m;i++){
        for(j=q[i-1].l;j<=q[i-1].r&&j<q[i].l;j++)
            update(ran[j],-1);
        for(j=q[i].l<q[i-1].r+1?q[i-1].r+1:q[i].l;j<=q[i].r;j++)
            update(ran[j],1);
        int num=find_kth(q[i].kx);
        ans[q[i].id]=x[num];
    }
    for(i=1;i<=m;i++) printf("%d\n",ans[i]);
    return 0;
}
posted @ 2012-05-17 16:59  Because Of You  Views(790)  Comments(0Edit  收藏  举报