首页 诗词 字典 板报 句子 名言 友答 励志 学校 网站地图
当前位置: 首页 > 教程频道 > 开发语言 > 编程 >

POJ 2104 & HDU 2665 K-th Number (区划树)

2013-09-07 
POJ 2104 & HDU 2665 K-th Number (划分树)题意不用说了,就是询问x次,指定区间的第k小的.................

POJ 2104 & HDU 2665 K-th Number (划分树)

题意不用说了,就是询问x次,指定区间的第k小的值....................


表示太弱了.......看了许久还是不太理解划分树内涵,先把偷来的模板留着

#include <iostream>#include <algorithm>#include <cmath>#include<functional>#include <cstdio>#include <cstdlib>#include <cstring>#include <string>#include <vector>#include <set>#include <queue>#include <stack>#include <climits>//形如INT_MAX一类的#define MAX 100005#define INF 0x7FFFFFFF#define L(x) x << 1#define R(x) x << 1 | 1using namespace std;struct Seg_Tree {    int l,r,mid;} tr[MAX*4];int len;int sorted[MAX];int lef[20][MAX];int val[20][MAX];void build(int l,int r,int step,int x) {    tr[x].l = l;    tr[x].r = r;    tr[x].mid = (l + r) >> 1;    if(tr[x].l == tr[x].r) return ;    int mid = tr[x].mid;    int lsame = mid - l + 1;//lsame表示和val_mid相等且分到左边的    for(int i = l ; i <= r ; i ++) {        if(val[step][i] < sorted[mid]) {            lsame --;//先假设左边的数(mid - l + 1)个都等于val_mid,然后把实际上小于val_mid的减去        }    }    int lpos = l;    int rpos = mid + 1;    int same = 0;    for(int i = l ; i <= r ; i ++) {        if(i == l) {            lef[step][i] = 0;//lef[i]表示[ tr[x].l , i ]区域里有多少个数分到左边        } else {            lef[step][i] = lef[step][i-1];        }        if(val[step][i] < sorted[mid]) {            lef[step][i] ++;            val[step + 1][lpos++] = val[step][i];        } else if(val[step][i] > sorted[mid]) {            val[step+1][rpos++] = val[step][i];        } else {            if(same < lsame) {//有lsame的数是分到左边的                same ++;                lef[step][i] ++;                val[step+1][lpos++] = val[step][i];            } else {                val[step+1][rpos++] = val[step][i];            }        }    }    build(l,mid,step+1,L(x));    build(mid+1,r,step+1,R(x));}int query(int l,int r,int k,int step,int x) {    if(l == r) {        return val[step][l];    }    int s;//s表示[l , r]有多少个分到左边    int ss;//ss表示 [tr[x].l , l-1 ]有多少个分到左边    if(l == tr[x].l) {        s = lef[step][r];        ss = 0;    } else {        s = lef[step][r] - lef[step][l-1];        ss = lef[step][l-1];    }    if(s >= k) {//有多于k个分到左边,显然去左儿子区间找第k个        int newl = tr[x].l + ss;        int newr = tr[x].l + ss + s - 1;//计算出新的映射区间        return query(newl,newr,k,step+1,L(x));    } else {        int mid = tr[x].mid;        int bb = l - tr[x].l - ss;//bb表示 [tr[x].l , l-1 ]有多少个分到右边        int b = r - l + 1 - s;//b表示 [l , r]有多少个分到右边        int newl = mid + bb + 1;        int newr = mid + bb + b;        return query(newl,newr,k-s,step+1,R(x));    }}int n,m,l,r,k;int main() {    while(scanf("%d%d",&n,&m) != EOF) {        for(int i=1; i<=n; i++) {            scanf("%d",&val[0][i]);            sorted[i] = val[0][i];        }        sort(sorted + 1,sorted + 1 + n);        build(1,n,0,1);        for(int i=0; i<m; i++) {            scanf("%d%d%d",&l,&r,&k);            printf("%d\n",query(l,r,k,0,1));        }    }    return 0;}


热点排行