Hustoj (poj2104)线段树(划分树)

来源:互联网 发布:淘宝宝贝图片拍摄技巧 编辑:程序博客网 时间:2024/06/05 12:02
昨天做hust线段树专题的时候,可是不懂,后来查了网上的解题报告,才知道是应用划分树来计算的,因此这两天就学习划分树,
按照我个人的理解,划分树其基本思想就是通过如下的步骤
1.增加一个数组,将原来的数组信息排序号放在该数组上
2.建立一个课线段树(是根据排好序的数组来的),取中间的数字,把小于该数字的加入到左子树中,大于的加入到右子树中去,同时以一个二维数组来记录在该数之前有多少个数字已经加入到左子树中去(是为了后面查询的操作)
3.查询
通过LINK:http://vjudge.net/vjudge/contest/view.action?cid=57851#problem/E
就是poj的2104的题目来解释
下面这个是带有详细解释的代码
#define M 100001struct Seg_Tree{    int left,right;    int mid() {        return (left + right) >> 1;    }}tt[M*4];int len;int sorted[M];int toLeft[20][M];int val[20][M]; void build(int l,int r,int d,int idx) //build(1,n,0,1); {    tt[idx].left = l;    tt[idx].right = r;    if(tt[idx].left == tt[idx].right)    return ;    int mid = tt[idx].mid();    int lsame = mid - l + 1;//lsame表示和val_mid相等且分到左边的    for(int i = l ; i <= r ; i ++)    {        if(val[d][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) {            toLeft[d][i] = 0;//toLeft[i]表示[ tt[idx].left , i ]区域里有多少个数分到左边        } else {            toLeft[d][i] = toLeft[d][i-1];        }        if(val[d][i] < sorted[mid]) {            toLeft[d][i] ++;            val[d+1][lpos++] = val[d][i];        } else if(val[d][i] > sorted[mid]) {            val[d+1][rpos++] = val[d][i];        } else {            if(same < lsame) {//有lsame的数是分到左边的                same ++;                toLeft[d][i] ++;                val[d+1][lpos++] = val[d][i];            } else {                val[d+1][rpos++] = val[d][i];            }        }    }    build(l,mid,d+1,LL(idx));    build(mid+1,r,d+1,RR(idx));} int query(int l,int r,int k,int d,int idx) {    if(l == r) {        return val[d][l];    }    int s;//s表示[ l , r ]有多少个分到左边    int ss;//ss表示 [tt[idx].left , l-1 ]有多少个分到左边    if(l == tt[idx].left) {        s = toLeft[d][r];        ss = 0;    } else     {        s = toLeft[d][r] - toLeft[d][l-1];        ss = toLeft[d][l-1];    }    if(s >= k) {  //有多于k个分到左边,显然去左儿子区间找第k个        int newl = tt[idx].left + ss;        int newr = tt[idx].left + ss + s - 1;//计算出新的映射区间,这里减去1是因为那个tt【idx】+ss已经包含了[l,r]中的数,因此要减去1         return query(newl,newr,k,d+1,LL(idx));    } else //s<k;就是说左边的数不够,因此要到右边去找 {        int mid = tt[idx].mid();        int bb = l - tt[idx].left - ss;//bb表示 [tt[idx].left , 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,d+1,RR(idx));    }} int main() {    int T;    scanf("%d",&T);    while(T --) {        int n , m;        scanf("%d%d",&n,&m);        FOR(i,1,n+1) {            scanf("%d",&val[0][i]);            sorted[i] = val[0][i];        }        sort(sorted + 1 , sorted + n + 1);        build(1,n,0,1);        while(m --) {            int l,r,k;            scanf("%d%d%d",&l,&r,&k);            printf("%d\n",query(l,r,k,0,1));        }    }    return 0;}

AC CODE
#include<stdio.h>#include<iostream>#include<algorithm>using namespace std;#define M 100010struct Seg_Tree{ int left,right;int mid(){ return (left+right)>>1;}   }tt[M*4];int len;int sorted[M];int toLeft[20][M];int val[20][M];void build(int l,int r,int d,int idx){  tt[idx].left=l;  tt[idx].right=r;  if(tt[idx].left==tt[idx].right) return;  int mid=tt[idx].mid();  int Isame=mid-l+1;  for(int i=l;i<=r;i++)  {     if(val[d][i]<sorted[mid])       Isame--;  }  int lpos=l;  int rpos=mid+1;  int same=0;  for(int i=l;i<=r;i++)  {     if(i==l)     {     toLeft[d][i]=0;     }     else     {    toLeft[d][i]=toLeft[d][i-1]; } if(val[d][i]<sorted[mid]) {       toLeft[d][i]++;       val[d+1][lpos++]=val[d][i];     }     else if(val[d][i]>sorted[mid])     {      val[d+1][rpos++]=val[d][i];     }     else      {      if(same<Isame)      {   same++;   toLeft[d][i]++;   val[d+1][lpos++]=val[d][i];        }        else        { val[d+1][rpos++]=val[d][i];}     }  }  build(l,mid,d+1,idx*2);  build(mid+1,r,d+1,idx*2+1);}int query(int l, int r, int k, int d, int idx){ if(l==r)   return val[d][l];    int s;    int ss;    if(l==tt[idx].left)    {     s=toLeft[d][r];     ss=0;    }    else     {    s=toLeft[d][r]-toLeft[d][l-1];    ss=toLeft[d][l-1];    }    if(s>=k)    {  int newl=tt[idx].left+ss;  int newr=tt[idx].left+ss+s-1;  return query(newl,newr,k,d+1,idx*2);    }    else     {    int mid=tt[idx].mid();    int bb=l-tt[idx].left-ss;    int b=r-l+1-s;    int newl=mid+bb+1;    int newr=mid+bb+b;    return query(newl,newr,k-s,d+1,idx*2+1);    }}int main(void){ int n,m; 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+n+1);build(1,n,0,1);while(m--){           int a, b,c;           scanf("%d %d %d",&a,&b,&c);           printf("%d\n",query(a,b,c,0,1));        }    } return 0;}

继续学习线段树!KEEP IT ON
0 0
原创粉丝点击
热门问题 老师的惩罚 人脸识别 我在镇武司摸鱼那些年 重生之率土为王 我在大康的咸鱼生活 盘龙之生命进化 天生仙种 凡人之先天五行 春回大明朝 姑娘不必设防,我是瞎子 顾客老嫌瓷砖贵怎么办 公司的公章丢了怎么办 物业不给充电费怎么办 怎么办社保卡去哪里办 单位没给社保卡怎么办 诈骗链接点开了怎么办 私人老板拖欠工资不给怎么办 辞职了工资不发怎么办 老板欠工资不给怎么办 投资平台跑路了怎么办 眼镜太松往下滑怎么办 塑胶水管管断了怎么办 淘宝排名靠后了怎么办 我有古董想出售怎么办 被拍卖公司骗了怎么办 苹果4s铃声太小怎么办 新号码注册微信怎么办 uc不能下种子了怎么办 刚出生的小牛喘怎么办 回奶之后有硬块怎么办 回奶第十天硬块怎么办 断奶期间乳房有硬块怎么办 断奶后乳房有肿块怎么办 北京一证通到期怎么办 没做过后勤的人怎么办 别样app被税了怎么办 人肉代购被税了怎么办 网易考拉被税了怎么办 家住乐清被税了怎么办 糖耐结果高了怎么办 35岁之后死档案怎么办 档案被自己拆了怎么办 超过35岁的死档怎么办 医保卡和社保卡怎么办 吴江市民卡丢了怎么办 小人领导整你该怎么办 哥特王朝3死了怎么办 索尼z3无限重启怎么办 三星s7用久了卡怎么办 手机进了一点水怎么办 淘宝登不上去了怎么办