poj之旅——2104
来源:互联网 发布:防攻击软件 编辑:程序博客网 时间:2024/06/11 13:10
题目:给出一个数列,对于每个查询(i,j,k),输出ai.....aj中排序后第k个数。
分析:
其实就是线段树的运用。
二分答案,然后对于i...j计算小于k的数字个数,这个用线段树模拟归并排序,然后如果当前区间被i....j包含,那么就返回这个区间的二分后的结果,否则查找子区间。
跟AC的程序对拍十几个极端数据,可是死都不过,不懂。线段树就是我的克星。
参考程序:
#include<cstdio>#include<algorithm>#include<vector>#include<cstring>using namespace std;const int maxn=110000;vector<int> c[4*maxn];int a[maxn],b[maxn];int n;void build(int p,int l,int r){if (l+1==r)c[p].push_back(a[l]);else{int mid=(l+r)>>1;int lch=2*p,rch=2*p+1;build(lch,l,mid);build(rch,mid,r);c[p].resize(r-l);merge(c[lch].begin(),c[lch].end(),c[rch].begin(),c[rch].end(),c[p].begin());}}int query(int p,int l,int r,int ql,int qr,int x){if (qr<=l || r<=ql)return 0;elseif (ql<=l && r<=qr){return upper_bound(c[p].begin(),c[p].end(),x)-c[p].begin();}else{int mid=(l+r)>>1,t=0;if (ql<mid)t+=query(2*p,l,mid,ql,qr,x);if (mid<qr)t+=query(2*p+1,mid,r,ql,qr,x);return t;}}int main(){int T;while (scanf("%d%d",&n,&T)==2){ for (int i=1;i<=n;i++){ scanf("%d",&a[i]); b[i]=a[i]; } sort(b+1,b+n+1); build(1,1,n+1); while (T--){ int ql,qr,K; scanf("%d%d%d",&ql,&qr,&K); int l=-1,r=n+1; while (l<r){ int mid=(l+r)>>1; if (query(1,1,n+1,ql,qr+1,b[mid])>=K)r=mid; else l=mid+1; } printf("%d\n",b[l]);}}return 0;}
正确的:
#include<iostream> #include<cstring> #include<cstdio> #include<vector> #include<cmath> #include<algorithm> #define maxn 100000 using namespace std; vector<int> dat[4*maxn + 50]; //线段树的数据 int a[maxn + 50]; int n, q; //构建线段树 //k是节点的编号,和区间[l, r)对应 void build(int k, int l, int r) { if (r - l == 1) { dat[k].push_back(a[l]); return; } int lc = k << 1, rc = k << 1 | 1; build(lc, l, (l + r) / 2); build(rc, (l + r) / 2, r); dat[k].resize(r - l); //利用STL的merge函数把两个儿子的数列合并 merge(dat[lc].begin(), dat[lc].end(), dat[rc].begin(), dat[rc].end(),dat[k].begin()); } //计算[i, j)中不超过x的数的个数 //k是节点的编号,和区间[l, r)对应 int query(int i, int j, int x, int k, int l, int r) { if (j <= l || r <= i) //完全不相交 return 0; else if (i <= l&&r <= j){ //完全包含在里面 return upper_bound(dat[k].begin(), dat[k].end(), x) - dat[k].begin(); } else { //对儿子递归地计算 int lcnt = query(i, j, x, k << 1, l, (l + r) / 2); int rcnt = query(i, j, x, k << 1 | 1, (l + r) / 2, r); return lcnt + rcnt; } } int search(int x, int y, int k) { int l = -1000000000 - 1; int r = -l + 2; while (l < r){ int mid = (l + r) >> 1; int num = query(x, y+1, mid, 1, 1, n+1); if (k <= num) r = mid; else{ l = mid + 1; } } return l; } int main() { freopen("make.out","r",stdin);freopen("out.out","w",stdout); while (cin >> n >> q) { for (int i = 1; i <= n; i++){ scanf("%d", a + i); } build(1, 1, n + 1); int li, ri, ki; for (int i = 0; i < q; i++){ scanf("%d%d%d", &li, &ri, &ki); printf("%d\n", search(li, ri, ki)); } } return 0; }
0 0
- poj之旅——2104
- poj之旅——3258
- poj之旅——3273
- poj之旅——3104
- poj之旅——3045
- poj之旅——2976
- poj之旅——3111。
- poj之旅——3579
- poj之旅——1979
- poj之旅——3009
- poj之旅——3669
- poj之旅——2718
- poj之旅——3187
- poj之旅——3050
- poj之旅——2376
- poj之旅——1328
- poj之旅——3190
- poj之旅——2393
- java学习注意事项
- 【NOIP 模拟题】[T2]宝藏(树形dp)
- 机械键盘测试(1)——序
- poj 2823 Sliding Window(单调队列模板)
- Ant之build.xml(三)
- poj之旅——2104
- hdu1874 单源最短路Dijkstra
- hibernate进阶 (8)双向多对一
- java 薪酬接口
- 求GCD(最大公约数)的算法
- 说说泛型
- IntelliJ IDEA创建项目技巧
- SSH---Structs初级篇1
- java对象内存到底占用多少