题目:http://www.spoj.com/problems/ORDERS/ and http://acm.hdu.edu.cn/showproblem.php?pid=2852
题意:spoj227:告诉每个位置前面有多少个数比当前位置小,求出原序列。hdu2852:设计一个容器,支持几种操作:增加/删除元素,求容器中比a大的数中第k小的数是多少。
分析:两个题思路都是求数组里面的第K小的数。开始一直在找O(N*logN)的方法,后来发现O(N*logN*logN)也是可以过的。。。两步:和先前的逆序数一样先用树状数组处理好比x小的数有多少个,然后二分~(值是单调的)
spoj227代码:
#include <iostream> #include <cstdio> #include <cstring> using namespace std; const int maxn = 2e5+6; int lowbit[maxn],a[maxn],tree[maxn]; void GetLowbit() { for(int i=1;i<maxn;i++) lowbit[i]=i&-i; } void update(int x,int v) { for(int i=x;i<maxn && i;i+=lowbit[i]) tree[i]+=v; } int query(int x) { int ret(0); for(int i=x;i>0;i-=lowbit[i]) ret+=tree[i]; return ret; } int Find(int x,int n) { int ret=1e9,down=1,mid,up=n,v; while(down<=up) { mid=(down+up)>>1; v=query(mid); if(v>=x) { up=mid-1; if(mid<ret && x==v) ret=mid; } else down=mid+1; } return ret; } int main() { GetLowbit(); int ncase,n,x,y,v,i,j; scanf("%d",&ncase); while(ncase--) { scanf("%d",&n); memset(tree,0,sizeof(tree[0])*(n+3)); for(i=1;i<=n;i++) { update(i,1); scanf("%d",&a[i]); } for(i=n;i>=1;i--) { a[i]=Find(i-a[i],n); update(a[i],-1); } for(i=1;i<n;i++) printf("%d ",a[i]); printf("%d\n",a[n]); } return 0; }
#include <iostream> #include <cstdio> #include <cstring> using namespace std; const int maxn = 1e5+6; int tree[maxn],cnt[maxn],lowbit[maxn]; void GetLowbit() { for(int i=1;i<maxn;i++) lowbit[i]=i&-i; } void update(int x,int v) { for(int i=x;i<maxn && i;i+=lowbit[i]) tree[i]+=v; } int query(int x) { int ret(0); for(int i=x;i>0;i-=lowbit[i]) ret+=tree[i]; return ret; } int Find(int a,int k) { int down=a+1,mid,up=maxn-1,c=query(a),v,ret=1e9; while(down<=up) { mid=(down+up)>>1; v=query(mid)-c; if(v>=k) { up=mid-1; if(ret>mid) ret=mid; } else down=mid+1; } return ret; } int main() { GetLowbit(); int q,a,k,tp,v; while(scanf("%d",&q)!=EOF) { memset(tree,0,sizeof(tree)); memset(cnt,0,sizeof(cnt)); while(q--) { scanf("%d",&tp); if(tp==0) { scanf("%d",&v); cnt[v]++; update(v,1); } else if(tp==1) { scanf("%d",&v); if(cnt[v]>0) { cnt[v]--; update(v,-1); } else puts("No Elment!"); } else { scanf("%d%d",&a,&k); int num=query(maxn-1)-query(a); if(num<k) puts("Not Find!"); else printf("%d\n",Find(a,k)); } } } return 0; }
版权声明:本文为博主原创文章,未经博主允许不得转载。
树状数组求第K小值 (spoj227 Ordering the Soldiers && hdu2852 KiKi's K-Number)
原文地址:http://blog.csdn.net/w20810/article/details/46981599