hdu 4417,poj 2104 划分树(模版)归并树(模版)
这次是彻底把划分树搞明确了,与此同一时候发现了模版的重要性。敲代码一个字符都不能错啊~~~
划分树具体解释:点击打开链接
题意:求一组数列中随意区间不大于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 划分树(模版)归并树(模版)的更多相关文章
- poj 2104 K-th Number(主席树,详细有用)
poj 2104 K-th Number(主席树) 主席树就是持久化的线段树,添加的时候,每更新了一个节点的线段树都被保存下来了. 查询区间[L,R]操作的时候,只需要用第R棵树减去第L-1棵树就是区 ...
- K-th Number 线段树(归并树)+二分查找
K-th Number 题意:给定一个包含n个不同数的数列a1, a2, ..., an 和m个三元组表示的查询.对于每个查询(i, j, k), 输出ai, ai+1, ... ,aj的升序排列中第 ...
- K-th Number POJ - 2104 划分树
K-th Number You are working for Macrohard company in data structures department. After failing your ...
- HDU 2665 && POJ 2104(主席树)
http://poj.org/problem?id=2104 对权值进行建树(这个时候树的叶子是数组b的有序数列),然后二分查找原数列中每个数在有序数列中的位置(即第几小),对每一个前缀[1,i]建一 ...
- 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 ...
- HDU 3966 & POJ 3237 & HYSBZ 2243 & HRBUST 2064 树链剖分
树链剖分是一个很固定的套路 一般用来解决树上两点之间的路径更改与查询 思想是将一棵树分成不想交的几条链 并且由于dfs的顺序性 给每条链上的点或边标的号必定是连着的 那么每两个点之间的路径都可以拆成几 ...
- hdu 1540/POJ 2892 Tunnel Warfare 【线段树区间合并】
Tunnel Warfare Time Limit: 4000/2000 MS ...
- POJ 2104 K-th Number(主席树——附讲解)
Description You are working for Macrohard company in data structures department. After failing your ...
- HDU 4417 - Super Mario ( 划分树+二分 / 树状数组+离线处理+离散化)
题意:给一个数组,每次询问输出在区间[L,R]之间小于H的数字的个数. 此题可以使用划分树在线解决. 划分树可以快速查询区间第K小个数字.逆向思考,判断小于H的最大的一个数字是区间第几小数,即是答案. ...
随机推荐
- centos7刚安装需要的一些基础优化
基本操作一:更改主机名 centos7有一个新的修改主机名的命令hostnamectl # hostnamectl set-hostname --static benjamin # vim /etc/ ...
- qt include无法自动补齐
原因一: 检查cmake有没有include_directories 原因二: CmakeList.txt放错位置 原因三: 没有用qt new file来创建头文件
- MVC中Model和model的区别和用户
MVC中Model和model的区别,它们应该怎么用呢? 使用@model关键字可以定义一个Action里所对应的一个模型(经常可以叫他实体类). MVC的第一个字母M是Model,承载着View层和 ...
- AC日记——魔法少女LJJ bzoj 4399
魔法少女LJJ 思路: 动态开点权值线段树+启发式合并: 来,上代码: #include <cmath> #include <cstdio> #include <cstr ...
- Mysql 通用二进制包安装
通用二进制包安装 注意:这里有严格的平台问题: 使用时:centos5.5版本 (类似Windows下的绿色包) 下载(mirrors.sohu.com/mysql) 直接使用tar 解压到指 ...
- springmvc适配器的应用
前言 关于SpringMVC初始化ContextLoader中的XMLWebApplicationContext,以及DispatcherServlet初始化等等,这样的原理 已经有 ...
- Xamarin.Android真机测试提示[INSTALL_FAILED_UPDATE_INCOMPATIBLE]
Xamarin.Android真机测试提示[INSTALL_FAILED_UPDATE_INCOMPATIBLE] 使用真机测试的时候,出现以下错误提示: Deployment failed ...
- [NOIP模拟赛][并没有用二分][乱搞AC]
圆圈舞蹈 [问题描述] 熊大妈的奶牛在时针的带领下,围成了一个圆圈跳舞.由于没有严格的教育,奶牛们之间的间隔不一致. 奶牛想知道两只最远的奶牛到底隔了多远.奶牛A到B的距离为A顺时针走和逆时针走,到达 ...
- 关于android主线程异常NetworkOnMainThread不能访问网络
在Android开发中,如果你使用的是Android4.0以后,那你会发现,只要是写在主线程(就是Activity)中的HTTP请求,运行时都会报错,这是因为Android在4.0以后为了防止应用的A ...
- Visio中如何画面积一样的形状
如图,刚开始我想着用辅助的那些线(对齐),实现不了,后来想想直接复制就行了...........