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
原创粉丝点击