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 ...
随机推荐
- IDEA 回滚SVN更新内容
- 求最大公约数和小于n的所有质数
//algorithm.h enum SWAP_TYPE{MEMORY, COMPLEX}; struct SIntArray { int *pData; int num; SIntArray():p ...
- memcache的带图形界面监控工具memcachephp
memcache也有一款图形界面的监控工具(memcachephp),可以通过这个工具查看到局域网内所有部署memcache机器或者端口的memcache的运行情况,对我们监控memcache的缓存命 ...
- Wince常见操作
1.获取本地代码启动路径 //在代码启动路径下存在 Files 文件夹 Path.GetDirectoryName(Assembly.GetExecutingAssembly().GetName(). ...
- c3p0 config
c3p0-config.xml<?xml version="1.0" encoding="UTF-8"?> <c3p0-config> ...
- Window 下 Qt5 使用QMediaplayer 进行视频播放 流播放问题
int main(int argc, char *argv[]) { QApplication a(argc, argv); QWidget *widget = new QWidget; widget ...
- IDEA 编译时报错 “未结束的字符串文字” “解析时已经达到文件结尾”
Information:Using javac 1.7.0_75 to compile java sourcesInformation:java: Errors occurred while comp ...
- 阿里2014校招笔试题(南大)——利用thread和sleep生成字符串的伪随机序列
引言:题目具体描述记不大清了,大概是:Linux平台,利用线程调度的随机性和sleep的不准确性,生成一个各位均不相同的字符数组的伪随机序列.不得使用任何库函数.(这句记得清楚,当时在想线程库算不算, ...
- Tcpdump的详细用法
1. TCPDump介绍 TcpDump可以将网络中传送的数据包的"头"完全截获下来提供分析.它支持针对网络层.协议.主机.网络或端口的过滤,并提供and.or.not等逻辑语句来 ...
- diff & pattch 命令
基础知识 该命令的功能为逐行比较两个文本文件,列出其不同之处.它比comm命令完成更复杂的检查.它对给出的文件进行系统的检查,并显示出两个文件中所有不同的行,不要求事先对文件进行排序. 语法:diff ...