hdu 2665 Kth number(划分树模板)
http://acm.hdu.edu.cn/showproblem.php?pid=2665
[ poj 2104 2761 ] 改变一下输入就可以过
http://poj.org/problem?id=2104
http://poj.org/problem?id=2761
Kth number
Time Limit: 15000/5000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others) Total Submission(s): 3266 Accepted Submission(s): 1090
The second line contains n integers, describe the sequence. Each of following m lines contains three integers s, t, k. [s, t] indicates the interval and k indicates the kth big number in interval [s, t]
划分树是一种基于线段树的数据结构。主要用于快速求出(在log(n)的时间复杂度内)序列区间的第k大值 。
划分树和归并树都是用线段树作为辅助的,原理是基于快排 和归并排序 的。
划分树的建树过程基本就是模拟快排过程,取一个已经排过序的区间中值,然后把小于中值的点放左边,大于的放右边。并且记录d层第i个数之前(包括i)小于中值的放在左边的数。具体看下面代码注释。
查找其实是关键,因为再因查找[l,r]需要到某一点的左右孩子时需要把[l,r]更新。具体分如下几种情况讨论: 假设要在区间[l,r]中查找第k大元素,t为当前节点,lch,rch为左右孩子,left,mid为节点t左边界和中间点。
1、sum[r]-sum[l-1]>=k,查找lch[t],区间对应为[ left+sum[l-1] , left+sum[r]-1 ]
2、sum[r]-sum[l-1]<k,查找rch[t],区间对应为[ mid+1+l-left-sum[l-1] , mid+1+r-left-sum[r] ]
上面两个关系在纸上可以推出来,对着上图更容易理解关系式;
讲解转自:http://www.cnblogs.com/pony1993/archive/2012/07/17/2594544.html
AC代码:
#include<iostream>
#include<stdio.h>
#include<algorithm>
#include<string.h> using namespace std; #define N 100010 int sorted[N]; //排序完的数组
int toleft[][N]; //toleft[i][j]表示第i层从1到k有多少个数分入左边
int tree[][N]; //表示每层每个位置的值 void buildingTree(int l,int r,int dep)
{
if(l==r) return;
int mid = (l+r)>>;
int i,sum = mid-l+; //表示等于中间值而且被分入左边的个数
for(i=l;i<=r;i++)
{
if(tree[dep][i]<sorted[mid]) sum--;
}
int lpos=l;
int rpos=mid+;
for(i=l;i<=r;i++)
{
if(tree[dep][i]<sorted[mid]) //比中间的数小,分入左边
{
tree[dep+][lpos++]=tree[dep][i];
}
else if(tree[dep][i]==sorted[mid]&&sum>) //等于中间的数值,分入左边,直到sum==0后分到右边
{
tree[dep+][lpos++]=tree[dep][i];
sum--;
}
else //右边
{
tree[dep+][rpos++]=tree[dep][i];
}
toleft[dep][i] = toleft[dep][l-] + lpos - l; //从1到i放左边的个数
}
buildingTree(l,mid,dep+);
buildingTree(mid+,r,dep+);
} //查询区间第k大的数,[L,R]是大区间,[l,r]是要查询的小区间
int queryTree(int L,int R,int l,int r,int dep,int k)
{
if(l==r) return tree[dep][l];
int mid = (L+R)>>;
int cnt = toleft[dep][r] - toleft[dep][l-]; //[l,r]中位于左边的个数
if(cnt>=k)
{
int newl = L + toleft[dep][l-] - toleft[dep][L-]; //L+要查询的区间前被放在左边的个数
int newr = newl + cnt - ; //左端点加上查询区间会被放在左边的个数
return queryTree(L,mid,newl,newr,dep+,k);
}
else
{
int newr = r + toleft[dep][R] - toleft[dep][r];
int newl = newr - (r - l - cnt);
return queryTree(mid+,R,newl,newr,dep+,k-cnt);
}
} int main()
{
int t;
scanf("%d",&t);
while(t--)
{
int n,m,i;
scanf("%d%d",&n,&m);
for(i=;i<=n;i++)
{
scanf("%d",&tree[][i]);
sorted[i] = tree[][i];
}
sort(sorted+,sorted++n);
buildingTree(,n,);
while(m--)
{
int s,t,k;
scanf("%d%d%d",&s,&t,&k);
printf("%d\n",queryTree(,n,s,t,,k));
}
}
return ;
}
hdu 2665 Kth number(划分树模板)的更多相关文章
- HDU 2665 Kth number(划分树)
Kth number Time Limit: 15000/5000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others) Total S ...
- hdu 2665 Kth number 主席树
Kth number Time Limit: 15000/5000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others) Prob ...
- hdu 2665 Kth number_划分树
题意:求区间[a,b]的第k大 因为多次询问要用到划分树 #include <iostream> #include<cstdio> #include<algorithm& ...
- HDU - 2665 Kth number 主席树/可持久化权值线段树
题意 给一个数列,一些询问,问$[l,r]$中第$K$大的元素是哪一个 题解: 写法很多,主席树是最常用的一种之一 除此之外有:划分树,莫队分块,平衡树等 主席树的定义其实挺模糊, 一般认为就是可持久 ...
- POJ2104 K-th Number 划分树 模板题啊
/*Source Code Problem: 2104 User: 96655 Memory: 14808K Time: 1282MS Language: G++ Result: Accepted S ...
- hdu 2665 Kth number
划分树 /* HDU 2665 Kth number 划分树 */ #include<stdio.h> #include<iostream> #include<strin ...
- 主席树[可持久化线段树](hdu 2665 Kth number、SP 10628 Count on a tree、ZOJ 2112 Dynamic Rankings、codeforces 813E Army Creation、codeforces960F:Pathwalks )
在今天三黑(恶意评分刷上去的那种)两紫的智推中,突然出现了P3834 [模板]可持久化线段树 1(主席树)就突然有了不详的预感2333 果然...然后我gg了!被大佬虐了! hdu 2665 Kth ...
- [hdu2665]Kth number(划分树求区间第k大)
解题关键:划分树模板题. #include<cstdio> #include<cstring> #include<algorithm> #include<cs ...
- hdu 2665 Kth number(划分树)
Kth number Time Limit: 15000/5000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others) Total S ...
随机推荐
- 有关<action android:name="android.intent.action.DELETE" />
今天看一个病毒样本时遇到了这个Action,位于一个Activity节点下 通过真机测试与导师指导发现,这个Action的作用就相当于把其所在的应用加入到了“系统卸载程序”列表,当你卸载系统中的任一应 ...
- Spring-boot访问MongoDB
1.访问配置信息 package hello; import org.springframework.context.annotation.Bean; import org.springframewo ...
- Linux上安装Squall
Squall是Storm之上的类SQL查询工具,能够将类SQL语句转换成topology,然后提交给Storm运行. 安装Squall前要先安装Java和sbt(simple build tool), ...
- C++的三大特性之一继承
一.继承的相关基本概念 1.继承的定义 在C++中,可以使用继承来使新类得到已定义的一些类中的特性,这就好比与孩子从父亲母亲得到遗传类似,所以我们称原有的类为基类或父类,用原有类来生成新的类的 ...
- kali Linux 文本图形界面切换遇到的怪问题
前段装了在Virtual Box上装一个Kali Linux玩,然后设为了开机进入文本界面,后来遇到无法上网的问题,网上找到解决方法,说是NAT地址转换和host-only双网卡顺序问题,按照网上的说 ...
- C#控制台输入
学习C语言后,在学习C#会有一个很不适应的小毛病.那就是在C语言里面你可以在一行输入好几个数字或是字母然后分别赋给相应的变量.可是在C#里面就不一样了,它只能读取一行.要实现一个一个变量赋值那就只有一 ...
- 浅谈SqlCommand
初学asp.net 的菜鸟应该都会像我一样想尝试一下前后台的交互吧!特别是与数据库的交互.下面就来说一下自己的个人经历. SqlCommand 首先需要引入system.Date.SqlClient命 ...
- WEB前端优化一些经验技巧
引言: 1. 慢的页面可能会网站失去更多的用户. 2. 慢500ms意味着20%的用户将放弃访问(google) 3. 慢100ms意味着1%的用户将放弃交易(amazon) 前段时间偶然看到网上的两 ...
- c#调用c++ dll(二)
当对c++几种调用方式有了解以后我们可以试着写个c++动态连接库了,我们现在来写个简单的c++求和函数并把它封装成dll,供以后的c#调用 我们写dll的时候,个人认为,要写就要把dll写好,写标准, ...
- SharePoint 学习记事(一)
记录背景: 随着公司业务的拓展,为拿到更多的项目,让原本不太信任我们的美国大佬相信我们的实力,让在美国的销售发挥他的能力,所以公司在13年下半年筹划收购了一家美国本土的公司.大约400人的规模,这个公 ...