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; }