这次是彻底把划分树搞明确了,与此同一时候发现了模版的重要性。敲代码一个字符都不能错啊~~~

划分树具体解释:点击打开链接

题意:求一组数列中随意区间不大于h的个数。

这个题的做法是用二分查询  求给定区间内的中值再与K进行比較。

重点介绍划分树:

数据结构:

t[20][maxn] // 树结构,划分树存储

sum[20][maxn] // 记录该行[l,i] 中i到l有多少个存在左子树中

as[maxn]  //原始数组排序后结果

#include <stdio.h>
#include <string.h>
#include <math.h>
#include <bitset>
#include <iostream>
#include <algorithm>
#define inf 0x3fffffff
#define mid ((l+r)>>1)
const int maxn=100000+100;
typedef unsigned __int64 ull;
using namespace std;
int N,M; int t[30][maxn]; // 树结构,划分树存储
int sum[30][maxn]; // 记录该行[l,i] 中i到l有多少个存在左子树中
int as[maxn];//排序后数组 //建树是根据上一层建立下一层,所以t[p+1][ls++]=t[p][i]; l==r推断的条件放在循环后是为了让每一个元素都到最底层
void build(int p,int l,int r)
{
int ls=l,rs=mid+1;
int lm=0,i;
for(i=rs-1;i>=l;i--)// ls rs 左右子树開始的位置 lm 放入左子树的中值数目(避免中值过多树不平衡)
if(as[i]==as[mid]) lm++;
else break;
for(i=l;i<=r;i++)
{
if(i==l) sum[p][i]=0;//sum的计算若为初始则为0。注意这里的每行sum有多个分开的树
else sum[p][i]=sum[p][i-1];
if(t[p][i]==as[mid])
if(lm) //将部分中值的数放入左边
lm--,sum[p][i]++,t[p+1][ls++]=t[p][i];
else t[p+1][rs++]=t[p][i];
else if(t[p][i]<as[mid]) sum[p][i]++,t[p+1][ls++]=t[p][i];//小于中值放入左边
else t[p+1][rs++]=t[p][i];//大于放入右边。sum与其无关
}
if(l==r) return;
build(p+1,l,mid);
build(p+1,mid+1,r); }
/*
在p层,[l,r]范围内查询[ql,qr]中第K大数
l+s 跳过查询区间前放入左子树个数,l+sum[p][qr]-1 [l,qr]放入左子树的个数
ql-l-s 查询区间前放入右子树的个数,qr-l-sum[p][qr] [l,qr]放入右子树的个数
*/
int query(int p,int l,int r,int ql,int qr,int k)
{
if(l==r) return t[p][l];
int s,ss;//s是ql左边有多少放入下层左子树,ss是[ql,qr]中有多少放入下层左子树
if(ql==l)
s=0,ss=sum[p][qr];
else
s=sum[p][ql-1],ss=sum[p][qr]-s;
if(k<=ss)
return query(p+1,l,mid,l+s,l+sum[p][qr]-1,k);
else
return query(p+1,mid+1,r,mid+1+ ql-l-s,mid+1 +qr-l-sum[p][qr],k-ss);
} int main()
{
int T;
int n,m,cas=1;
int i,l,r,k;
scanf("%d",&T);
while(T--)
{
scanf("%d%d",&N,&M);
for(i=0;i<N;i++)
scanf("%d",as+i),t[0][i]=as[i];
sort(as,as+N);
build(0,0,N-1);
printf("Case %d:\n",cas++);
for(i=0;i<M;i++)
{
scanf("%d%d%d",&l,&r,&k);
int mi=1,ma=r-l+1,Mid,ans=r-l+2;
while(mi<=ma)
{
Mid=(mi+ma)>>1;
int tmp=query(0,0,N-1,l,r,Mid);
if(tmp>k)
{
ans=Mid;
ma=Mid-1;
}
else
mi=Mid+1;
}
printf("%d\n",ans-1);
} }
return 0;
}

归并树:

就是在归并过程中保存结果。由于归并排序与线段树建树类似都是自底向上,所以能够保存。(这个比划分树好理解多了)

#include<iostream>
#include<cstdio>
#include<cstring>
#include<queue>
#include<map>
#include<stack>
#include<algorithm>
#include<string>
#define LL long long
#define LD long double
#define eps 1e-7
#define inf 1<<30
#define MOD 1000000007
#define N 100005
using namespace std;
struct MergeTree{
int left,right,mid;
}tree[N*4];
int num[N],mer[20][N];
int n,q;
void create(int step,int l,int r,int deep){
tree[step].left=l;
tree[step].right=r;
tree[step].mid=(l+r)>>1;
if(l==r){
mer[deep][l]=num[l];
return;
}
create(step<<1,l,(l+r)/2,deep+1);
create((step<<1)|1,(l+r)/2+1,r,deep+1);
int i=l,j=(l+r)/2+1,p=l;
//归并排序。在建树的时候保存
while(i<=(l+r)/2&&j<=r){
if(mer[deep+1][i]>mer[deep+1][j])
mer[deep][p++]=mer[deep+1][j++];
else
mer[deep][p++]=mer[deep+1][i++];
}
while(i<=(l+r)/2)
mer[deep][p++]=mer[deep+1][i++];
while(j<=r)
mer[deep][p++]=mer[deep+1][j++];
}
int query(int step,int l,int r,int deep,int key){
if(tree[step].right<l||tree[step].left>r)
return 0;
if(tree[step].left>=l&&tree[step].right<=r)
//找到key在排序后的数组中的位置
return lower_bound(&mer[deep][tree[step].left],&mer[deep][tree[step].right]+1,key)-&mer[deep][tree[step].left];
return query(2*step,l,r,deep+1,key)+query(2*step+1,l,r,deep+1,key);
}
int slove(int l,int r,int k){
int high=n,low=1,mid;
//二分答案
while(low<high){
mid=(low+high+1)>>1;
int cnt=query(1,l,r,1,mer[1][mid]);
if(cnt<=k)
low=mid;
else
high=mid-1;
}
return mer[1][low];
}
int main(){
while(scanf("%d%d",&n,&q)!=EOF){
for(int i=1;i<=n;i++)
scanf("%d",&num[i]);
create(1,1,n,1);
while(q--){
int l,r,k;
scanf("%d%d%d",&l,&r,&k);
printf("%d\n",slove(l,r,k-1));
}
}
return 0;
}

hdu 4417,poj 2104 划分树(模版)归并树(模版)的更多相关文章

  1. poj 2104 K-th Number(主席树,详细有用)

    poj 2104 K-th Number(主席树) 主席树就是持久化的线段树,添加的时候,每更新了一个节点的线段树都被保存下来了. 查询区间[L,R]操作的时候,只需要用第R棵树减去第L-1棵树就是区 ...

  2. K-th Number 线段树(归并树)+二分查找

    K-th Number 题意:给定一个包含n个不同数的数列a1, a2, ..., an 和m个三元组表示的查询.对于每个查询(i, j, k), 输出ai, ai+1, ... ,aj的升序排列中第 ...

  3. K-th Number POJ - 2104 划分树

    K-th Number You are working for Macrohard company in data structures department. After failing your ...

  4. HDU 2665 && POJ 2104(主席树)

    http://poj.org/problem?id=2104 对权值进行建树(这个时候树的叶子是数组b的有序数列),然后二分查找原数列中每个数在有序数列中的位置(即第几小),对每一个前缀[1,i]建一 ...

  5. HDU 3265/POJ 3832 Posters(扫描线+线段树)(2009 Asia Ningbo Regional)

    Description Ted has a new house with a huge window. In this big summer, Ted decides to decorate the ...

  6. HDU 3966 & POJ 3237 & HYSBZ 2243 & HRBUST 2064 树链剖分

    树链剖分是一个很固定的套路 一般用来解决树上两点之间的路径更改与查询 思想是将一棵树分成不想交的几条链 并且由于dfs的顺序性 给每条链上的点或边标的号必定是连着的 那么每两个点之间的路径都可以拆成几 ...

  7. hdu 1540/POJ 2892 Tunnel Warfare 【线段树区间合并】

    Tunnel Warfare                                                             Time Limit: 4000/2000 MS ...

  8. POJ 2104 K-th Number(主席树——附讲解)

    Description You are working for Macrohard company in data structures department. After failing your ...

  9. HDU 4417 - Super Mario ( 划分树+二分 / 树状数组+离线处理+离散化)

    题意:给一个数组,每次询问输出在区间[L,R]之间小于H的数字的个数. 此题可以使用划分树在线解决. 划分树可以快速查询区间第K小个数字.逆向思考,判断小于H的最大的一个数字是区间第几小数,即是答案. ...

随机推荐

  1. Starting MySQL... ERROR! The server quit without updating PID file 问题解决

    今天遇到一个mysql起不来,不知为啥挂了,启动是下面的报错 Starting MySQL... ERROR! The server quit without updating PID file 后来 ...

  2. Jekyll搭建个人博客

    网上也有HEXO 搭建的博客,有人说使用 HEXO 在多台电脑上发布博客,操作起来并不是那么方便,所以使用Jekyll 来搭建. Jekyll配置 1,安装ruby环境 Windows系统使用Ruby ...

  3. delphi 开机自动运行代码

    unit Unit1;//download by http://www.codefans.netinterface uses  Windows,Registry, Messages, SysUtils ...

  4. HDU 1863 畅通工程 最小生成树

    思路: 比较典型的最小生成树的题目了..在这里用求最小生成树的经典算法K(Kruskal)算法和P(Prim)算法.我的 K 算法用的是结构体来存图,P 算法用的是邻接矩阵来存图,K算法的复杂度是O( ...

  5. 洛谷——P1595 信封问题

    P1595 信封问题 题目描述 某人写了n封信和n个信封,如果所有的信都装错了信封.求所有信都装错信封共有多少种不同情况. 输入输出格式 输入格式: 一个信封数n(n<=20) 输出格式: 一个 ...

  6. 六. 异常处理6.try语句的嵌套

    Try语句可以被嵌套.也就是说,一个try语句可以在另一个try块内部.每次进入try语句,异常的前后关系都会被推入堆栈.如果一个内部的try语句不含特殊异常的catch处理程序,堆栈将弹出,下一个t ...

  7. Intent创建Activity

    1,布局 <?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android ...

  8. 一篇不错的讲解Java异常的文章(转载)----感觉很不错,读了以后很有启发

    六种异常处理的陋习 你觉得自己是一个Java专家吗?是否肯定自己已经全面掌握了Java的异常处理机制?在下面这段代码中,你能够迅速找出异常处理的六个问题吗? OutputStreamWriter ou ...

  9. Scala和Java二种方式实战Spark Streaming开发

    一.Java方式开发 1.开发前准备:假定您以搭建好了Spark集群. 2.开发环境采用eclipse maven工程,需要添加Spark Streaming依赖. 3.Spark streaming ...

  10. ant 报 make sure you have it in your classpath

    检查build.xml的配置 build.xml配置出错,导致的这个问题