POJ - 2104 K-th Number (线段树,平方分割)

题目链接

题意,给你一组数据,m 个询问

每次询问,区间 [ i , j ] 中第 K 大的数是多少,

两个算法,一个是线段树,一个是平方分割。

一、线段树,

这次线段树的每个节点上记录的不是数值了,而是保存了一个序列。

然后二分结果,在线段树种查询这个结果在区间中排多少,最终把值找出来,

线段树节点保存数列是有序的,用到 STL 的一个merge 函数把两个儿子的数列合并。前提是两个儿子的数列也是有序的。

merge(dat[f[p].l].begin(),dat[f[p].l].end(),dat[f[p].r].begin(),dat[f[p].r].end(),dat[p].begin());

#include <vector>
#include <iostream>
#include <cstdio>
#include <algorithm>
using namespace std;
const int N = 1e5 + 10;
struct segtree{
    int l,r,a,b;
    int cal_mid(){
        return (a + b) / 2;
    }
}f[N*2];
vector<int>dat[N*2];
int n,m,k,c[N],t,x,y,z,d[N];
void build(int p, int a, int b){
    f[p].a = a; f[p].b = b;
    if (a + 1 == b){
        dat[p].push_back(c[a]);
        return;
    }
    int m = f[p].cal_mid();
    t++; f[p].l = t; build(t,a,m);
    t++; f[p].r = t; build(t,m,b);
    dat[p].resize(b-a);
    merge(dat[f[p].l].begin(),dat[f[p].l].end(),dat[f[p].r].begin(),dat[f[p].r].end(),dat[p].begin());
    return;
}
int Qurey(int p){
    int sum = 0;
    if (x <= f[p].a && y >= f[p].b-1){
        return  upper_bound(dat[p].begin(),dat[p].end(),d[k])-dat[p].begin();
    }
    int  m = f[p].cal_mid();
    if (x < m) sum += Qurey(f[p].l);
    if (y >= m) sum += Qurey(f[p].r);
    return sum;
}

int main() {
    scanf("%d%d",&n,&m);
    for (int i = 1; i <= n; i++) {
        scanf("%d", &c[i]);
        d[i] = c[i];
    }
    sort(d+1,d+n+1);
    t = 1;
    build(1,1,n+1);
    for (int i = 0; i < m; i++){
        scanf("%d%d%d",&x,&y,&z);
        int l = 1,r = n,ans,tt;
        while(l <= r){
             k = (l + r) / 2;
             tt = Qurey(1);
             if (tt < z) l = k +1; else {
                 ans = k;
                 r = k - 1;
             }
        }
       printf("%d\n",ans);
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/kidsummer/article/details/81227464