sdut 2610:Boring Counting(第四届山东省省赛原题,划分树 + 二分)
Boring Counting
Time Limit: 3000ms Memory limit: 65536K 有疑问?点这里^_^
题目描述
输入
For each case, the first line contains two numbers N and M (1 <= N, M <= 50000), the size of sequence P, the number of queries. The second line contains N numbers Pi(1 <= Pi <= 10^9), the number sequence P. Then there are M lines, each line contains four number L, R, A, B(1 <= L, R <= n, 1 <= A, B <= 10^9)
输出
示例输入
1
13 5
6 9 5 2 3 6 8 7 3 2 5 1 4
1 13 1 10
1 13 3 6
3 6 3 6
2 8 2 8
1 9 1 9
示例输出
Case #1:
13
7
3
6
9
提示
来源
这道题最直接的思路是对要求的区间排一下序,然后依次判断比较,记录下在范围[A,B]之内的数有多少个,即为结果。但是M即询问的次数范围在[1,50000],如果每询问一次都要排一次序的话,时间消耗过大,所以上来直接pass掉这种思路。


#include <iostream>
#include <stdio.h>
#include <algorithm>
using namespace std;
#define MAXN 100005
struct Divide_tree{
int arr[MAXN]; //原数组
int sorted[MAXN]; //排序后数组
int sum[][MAXN]; //记录第i层1~j划分到左子树的元素个数(包括j)
int dat[][MAXN]; //记录第i层元素序列
void build(int c,int L,int R) //建树,主要是建立sum[][]和dat[][]数组
{
int mid = (L+R)>>;
int lsame = mid-L+; //lsame用来记录和中间值val_mid相等的,且可以分到左孩子的数的个数
//简单来说就是可以放入左孩子的,与中间值val_mid相等的数的个数
int lp=L,rp=mid+; //当前节点的左孩子和右孩子存数的起点
for(int i=L;i<mid;i++) //获得一开始的lsame
if(sorted[i]<sorted[mid])
lsame--;
for(int i=L;i<=R;i++){ //从前往后遍历一遍,
//确定当前节点区间内的所有元素的归属(放在左孩子或者放在右孩子)
if(i==L) sum[c][i]=;
else sum[c][i]=sum[c][i-];
if(dat[c][i]<sorted[mid]){ //当前元素比中间值val_mid小,放入左孩子
dat[c+][lp++] = dat[c][i];
sum[c][i]++;
}
else if(dat[c][i]>sorted[mid]) //当前元素比中间值val_mid大,放入右孩子
dat[c+][rp++] = dat[c][i];
else{ //当前元素值与中间值val_mid相等,根据lsame数判断放入左孩子还是右孩子
if(lsame){
lsame--;
sum[c][i]++;
dat[c+][lp++]=sorted[mid];
}
else{
dat[c+][rp++]=sorted[mid];
}
}
}
if(L==R) return ; //递归出口,遇到叶子节点
build(c+,L,mid); //递归进入左孩子区间
build(c+,mid+,R); //递归进入右孩子区间
}
int query(int c,int L,int R,int ql,int qr,int k)
{
//c为树的层数,L,R为当前节点的区间范围,ql,qr为查询的区间范围,k为查询范围内第k大的数
if(L==R) //递归出口,返回第k大的数
return dat[c][L];
int s; //记录[L,ql-1]中进入左孩子的元素的个数
int ss; //记录[ql,qr]中进入左孩子的元素的个数
int mid=(L+R)>>;
if(L==ql){ //端点重合的情况,单独考虑
s=;
ss=sum[c][qr];
}
else {
s=sum[c][ql-];
ss=sum[c][qr]-s;
}
if(k<=ss) //左孩子的元素个数大于k个,说明第k大的元素一定在左孩子区间中,到左孩子中查询
return query(c+,L,mid,L+s,L+s+ss-,k);
else
return query(c+,mid+,R,mid++ql-s-L,mid++qr-s-ss-L,k-ss);
}
};
Divide_tree tree;
int L,R,A,B;
int N,M;
int downbearch(int low,int high) //找到第一个比B小的数是 第几大的数(用划分树)
{
int mid = (low+high+)>>;
while(low<high){
if( tree.query(,,N,L,R,mid)<=B ) //查询第mid大的数是否比下界B小。
//如果mid比B小,说明要找的位置在mid右边,low应该右移,即
low = mid;
else //否则,说明要找的位置应该在mid左边,即
high = mid-;
mid = (low+high+)>>;
}
if( tree.query(,,N,L,R,mid)<=B ) //找到了
return mid;
else
return -;
}
int upbearch(int low,int high) //找到第一个比A大的数是 第几大的数(用划分树)
{
int mid = (low+high+)>>;
while(low<high){
if( tree.query(,,N,L,R,mid)>=A ) //查询第mid大的数是否比上界A大。
//如果mid比A大,说明要找的位置在mid左边,high应该左移,即
high = mid;
else //否则,说明要找的位置应该在mid右边,即
low = mid+;
mid = (low+high)>>;
}
if(tree.query(,,N,L,R,mid)>=A ) //找到了
return mid;
else
return -;
}
int main()
{
int i,Case,T;
scanf("%d",&T);
for(Case=;Case<=T;Case++){
scanf("%d%d",&N,&M);
for(i=;i<=N;i++){ //输入
scanf("%d",&tree.arr[i]);
tree.sorted[i]=tree.dat[][i]=tree.arr[i];
}
sort(tree.sorted+,tree.sorted+N+);
tree.build(,,N);
printf("Case #%d:\n",Case);
for(i=;i<=M;i++){
scanf("%d%d%d%d",&L,&R,&A,&B);
int up = downbearch(,R-L+);
int down = upbearch(,R-L+);
if(up==-||down==-||A>B||L>R)
printf("0\n");
else printf("%d\n",up-down+);
}
}
return ;
}
Freecode : www.cnblogs.com/yym2013
sdut 2610:Boring Counting(第四届山东省省赛原题,划分树 + 二分)的更多相关文章
- sdut 2603:Rescue The Princess(第四届山东省省赛原题,计算几何,向量旋转 + 向量交点)
Rescue The Princess Time Limit: 1000ms Memory limit: 65536K 有疑问?点这里^_^ 题目描述 Several days ago, a b ...
- SDUT 2610 Boring Counting(离散化+主席树区间内的区间求和)
Boring Counting Time Limit: 3000MS Memory Limit: 65536KB Submit Statistic Discuss Problem Descriptio ...
- sdut 2416:Fruit Ninja II(第三届山东省省赛原题,数学题)
Fruit Ninja II Time Limit: 5000MS Memory limit: 65536K 题目描述 Have you ever played a popular game name ...
- sdut 2413:n a^o7 !(第三届山东省省赛原题,水题,字符串处理)
n a^o7 ! Time Limit: 1000MS Memory limit: 65536K 题目描述 All brave and intelligent fighters, next you w ...
- sdut 2162:The Android University ACM Team Selection Contest(第二届山东省省赛原题,模拟题)
The Android University ACM Team Selection Contest Time Limit: 1000ms Memory limit: 65536K 有疑问?点这里 ...
- sdut 2163:Identifiers(第二届山东省省赛原题,水题)
Identifiers Time Limit: 1000ms Memory limit: 65536K 有疑问?点这里^_^ 题目描述 Identifier is an important c ...
- sdut 2411:Pixel density(第三届山东省省赛原题,字符串处理)
Pixel density Time Limit: 1000ms Memory limit: 65536K 有疑问?点这里^_^ 题目描述 Pixels per inch (PPI) or pi ...
- sdut 2165:Crack Mathmen(第二届山东省省赛原题,数论)
Crack Mathmen Time Limit: 1000ms Memory limit: 65536K 有疑问?点这里^_^ 题目描述 Since mathmen take securit ...
- sdut 2159:Ivan comes again!(第一届山东省省赛原题,STL之set使用)
Ivan comes again! Time Limit: 1000ms Memory limit: 65536K 有疑问?点这里^_^ 题目描述 The Fairy Ivan gave Say ...
随机推荐
- PHP5.4开启zend opcache缓存
PHP5.5整合了zend opcache,但是5.4以下的需要自己安装. 介绍一下开启opcache方法,环境为wamp(php5.4.16) 下载dll文件 把php_opcache.dll放进p ...
- hadoop学习过程中一系列问题
12---修改host .修改主机名5.1 修改当前会话的主机名sudo hostname SY-0217查看当前会话的主机名hostname默认是我装Linux 虚机时输入的名字Ubuntu5.2 ...
- sql server2008 字符串的替换
DECLARE @TSql VARCHAR(MAX) SET @TSql =REPLACE(@TSql,'#PrimaryKey','0'); 1,@TSql将要替换的完整字符串 2,#Primary ...
- 【MavenWeb】初探:创建一个Maven Web项目
第一步:创建一个Simple的Maven项目 直接点下一步,把name上面的几个部分填写好,直接Finish即可. 就可以看到如下的结构: 注意点1:如果按照网上的其他一些做法来创建,你会发现少了sr ...
- symfony2 环境搭建笔记
本机环境:windows+xampp symfony下载:官网下载 环境配置: 1.下载后将symfony文件夹解压到xampp/htdocs中(最好改一下文件夹名,尽量小写) 2.Symfony2自 ...
- JS添加删除DIV
function addDiv(w,h){ //如果原来有“divCell”这个图层,先删除这个图层 deleteDiv(); //创建一个div var my = d ...
- C#错误之 System.Threading.ThreadAbortException:正在中止线程
参考:http://www.cnblogs.com/chendaoyin/archive/2013/06/27/3159211.html 1.开启一个子线程 //开启一个子线程,子线程调用方法 Met ...
- Qt 信号槽如何传递参数(或带参数的信号槽)
信号槽如何传递参数(或带参数的信号槽) 利用Qt进行程序开发时,有时需要信号槽来完成参数传递.带参数的信号槽在使用时,有几点需要注意的地 ...
- centos7.0改变用户创建目录组权限
centos7.0改变用户创建目录组权限可通过umask进行设置. 临时改变可通过umask命令进行设置 永久性改变,可通过修改~/.bash_profile的方式进行调整.
- SqlDateTime 溢出。
SqlDateTime 溢出.必须介于 1/1/1753 12:00:00 AM 和 12/31/9999 11:59:59 PM 之间 解决方法:不要怀疑自己的判断就是数据库字段里的datatime ...