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;

}

你可能感兴趣的:(poj)