Problem H:Boring Counting

Time Limit : 6000/3000ms (Java/Other)   Memory Limit : 65535/32768K (Java/Other)

Problem Description

In this problem you are given a number sequence P consisting of N integer and Pi is the ith element in the sequence. Now you task is to answer a list of queries, for each query, please tell us among [L, R], how many Pi is not less than A and not greater than B( L<= i <= R). In other words, your task is to count the number of Pi (L <= i <= R,  A <= Pi <= B).

Input

In the first line there is an integer T (1 < T <= 50), indicates the number of test cases.
        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)

Output

For each case, at first output a line
‘Case #c:’, c is the case number start from 1. Then for each query output a
line contains the answer.

Sample Input

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

Sample Output

Case
#1:

13

7

3

6

9

给你n个数和m条询问,每次查询区间[l,r]中满足A<=x<=B的x的个数。

感觉很不错的一道题,考察主席树的应用。

关于主席树,请参考:http://seter.is-programmer.com/posts/31907.html

建立n棵线段树,线段树root[i]代表区间[1,i]之间一段数字区间出现的次数。

对于每一棵线段树,每个节点表示一个区间[a,b],记录满足a<=x<=b的x的个数。

因为线段树root[i]是在线段树root[i-1]的基础上增加了一个数得到的,所以可以由root[i-1]得到root[i]。

由于每棵线段树的大小形态都是一样的,而且初始值全都是0,那每个线段树都初始化不是太浪费了?所以一开始只要建一棵空树即可。

然后是在某棵树上修改一个数字,由于和其他树相关联,所以不能在原来的树上改,必须弄个新的出来。难道要弄一棵新树?不是的,由于一个数字的更改只影响了一条从这个叶子节点到根的路径,所以只要只有这条路径是新的,另外都没有改变。比如对于某个节点,要往右边走,那么左边那些就不用新建,只要用个指针链到原树的此节点左边就可以了,这个步骤的前提也是线段树的形态一样。

n是数字个数,这个步骤的空间复杂度显然是O(logn)。

所有树节点的空间消耗为:O(n*4+nlogn)

预处理得到所有的root[i]。

查询时在两棵线段树root[R]和root[L-1]中分别查询区间[A,B]中数的个数,相减即是结果。

本题的时间复杂度:建树:O(n)+预处理O(nlogn)+查询O(logn)

 #include <cstdio>
#include <cstring>
#include <cstdlib>
#include <algorithm> using namespace std; #define lson l, m, rt->left
#define rson m + 1, r, rt->right const int MAXN = ;
const int INF = (1e9)+; struct Node
{
int sum; //存储区间[A, B]之间一共有多少个数
Node *left, *right;
}; Node *root[MAXN];
Node ChairTree[ MAXN * ];
Node *idx; int pos[MAXN]; //处于位置i的数排第几
int num[MAXN]; //排好序并去重的原始数,相当于把所有数离散化之后的结果
int p[MAXN]; //排第i的是哪个数
int cnt, n, Q; bool cmp( int a, int b )
{
return pos[a] < pos[b];
} Node *nextNode()
{
idx->sum = ;
idx->left = idx->right = NULL;
return idx++;
} Node *copyNode( Node *ori )
{
idx->sum = ori->sum;
idx->left = ori->left;
idx->right = ori->right;
return idx++;
} void PushUp( Node *rt )
{
rt->sum = rt->left->sum + rt->right->sum;
return;
} void build( int l, int r, Node* rt ) //建立一个空树
{
if ( l == r ) return; int m = ( l + r ) >> ; rt->left = nextNode();
rt->right = nextNode(); build( lson );
build( rson ); return;
} void init()
{
scanf( "%d%d", &n, &Q ); for ( int i = ; i <= n; ++i )
{
scanf( "%d", &pos[i] );
p[i] = i;
}
sort( p + , p + + n, cmp ); int pre = -INF;
cnt = ;
for ( int i = ; i <= n; ++i ) //离散化+去重
{
if ( pos[ p[i] ] == pre )
pos[ p[i] ] = cnt;
else
{
pre = pos[ p[i] ];
num[ ++cnt ] = pos[ p[i] ];
pos[ p[i] ] = cnt;
}
}
return;
} Node *add( int val, int l, int r, Node* rt ) //根据上一棵树构造下一棵树
{
Node *temp = copyNode( rt ); if ( l == r )
{
temp->sum += ;
return temp;
}
int m = ( l + r ) >> ;
if ( val <= m ) temp->left = add( val, lson );
else temp->right = add( val, rson );
PushUp( temp ); return temp;
} int Query( int L, int R, int l, int r, Node* treeL, Node* treeR )
{
if ( L <= l && r <= R )
{
return treeR->sum - treeL->sum;
}
int res = ; int m = ( l + r ) >> ;
if ( L <= m ) res += Query( L, R, l, m, treeL->left, treeR->left );
if ( R > m ) res += Query( L, R, m + , r, treeL->right, treeR->right );
return res;
} void chuli()
{
idx = ChairTree;
root[] = nextNode();
build( , cnt, root[] ); //建立一颗空树 for ( int i = ; i <= n; ++i )
root[i] = add( pos[i], , cnt, root[i - ] ); //根据第i-1棵树构造第i棵树
return;
} int BiSearch1( int tar ) //查询最左边的 >= x 的数
{
int low = , high = cnt;
int mid, ans = -;
while ( low <= high )
{
mid = ( low + high ) >> ;
if ( num[mid] >= tar )
{
ans = mid;
high = mid - ;
}
else low = mid + ;
}
return ans;
} int BiSearch2( int tar ) //查询最右边的 <= x 的数
{
int low = , high = cnt;
int mid, ans = -;
while ( low <= high )
{
mid = ( low + high ) >> ;
if ( num[mid] <= tar )
{
ans = mid;
low = mid + ;
}
else high = mid - ;
}
return ans;
} int main()
{
int T, cas = ;
scanf( "%d", &T );
while ( T-- )
{
init();
chuli(); printf( "Case #%d:\n", ++cas );
while ( Q-- )
{
int l, r, a, b;
scanf("%d%d%d%d", &l, &r, &a, &b );
int u = BiSearch1( a );
int v = BiSearch2( b );
if ( u == - || v == - )
{
puts("");
continue;
}
printf( "%d\n", Query( u, v, , cnt, root[l - ], root[r] ) );
}
}
return ;
}

UPC 2224 / “浪潮杯”山东省第四届ACM大学生程序设计竞赛 1008 Boring Counting 主席树的更多相关文章

  1. “浪潮杯”山东省第五届ACM大学生程序设计竞赛(总结贴)

    第一次參加省赛有点小激动,尽管是作为打星队參赛,但心情却是上下起伏. 5月9号晚上11点多到威海,有点略冷.可是空气比淄博好多了,大家到了旅馆的时候都非常晚了,抱怨了一下三星级的酒店的待遇,喝杯咖啡早 ...

  2. 2012年"浪潮杯"山东省第三届ACM大学生程序设计竞赛--n a^o7 ! 分类: 比赛 2015-06-09 17:16 14人阅读 评论(0) 收藏

    n a^o7 ! Time Limit: 1000ms   Memory limit: 65536K  有疑问?点这里^_^ 题目描述 All brave and intelligent fighte ...

  3. 山东省第四届ACM大学生程序设计竞赛解题报告(部分)

    2013年"浪潮杯"山东省第四届ACM大学生程序设计竞赛排名:http://acm.upc.edu.cn/ranklist/ 一.第J题坑爹大水题,模拟一下就行了 J:Contes ...

  4. Alice and Bob(2013年山东省第四届ACM大学生程序设计竞赛)

    Alice and Bob Time Limit: 1000ms   Memory limit: 65536K 题目描述 Alice and Bob like playing games very m ...

  5. 2013年山东省第四届ACM大学生程序设计竞赛-最后一道大水题:Contest Print Server

    点击打开链接 2226: Contest Print Server Time Limit: 1 Sec  Memory Limit: 128 MB Submit: 53  Solved: 18 [Su ...

  6. sdut Mountain Subsequences 2013年山东省第四届ACM大学生程序设计竞赛

    Mountain Subsequences 题目描述 Coco is a beautiful ACMer girl living in a very beautiful mountain. There ...

  7. 2013年山东省第四届ACM大学生程序设计竞赛J题:Contest Print Server

    题目描述     In ACM/ICPC on-site contests ,3 students share 1 computer,so you can print your source code ...

  8. 2013年山东省第四届ACM大学生程序设计竞赛 Alice and Bob

      Alice and Bob Time Limit: 1000ms   Memory limit: 65536K 题目描述 Alice and Bob like playing games very ...

  9. 2013年山东省第四届ACM大学生程序设计竞赛E题:Alice and Bob

    题目描述 Alice and Bob like playing games very much.Today, they introduce a new game. There is a polynom ...

随机推荐

  1. 【转载】Powershell在世纪互联Office365中批量将用户添加到组

    $NewUserPath = ".\Office365AddUserToGroup.csv" $NewUsers = import-csv $NewUserPath foreach ...

  2. 菜鸟学习Struts——配置Struts环境

    刚开始学习Struts,它通过采用JavaServlet/JSP技术,实现了基于Java EEWeb应用的MVC设计模式的应用框架,是MVC经典设计模式中的一个经典产品. 要用到Struts就要学会配 ...

  3. SQL左连接、右连接和内连接的简单示例

    left join(左联接) 返回包括左表中的所有记录和右表中联结字段相等的记录: right join(右联接) 返回包括右表中的所有记录和左表中联结字段相等的记录: inner join(等值连接 ...

  4. SSHDroid(SSH Server for Android)通过PC或命令连接android

    1.下载berserker.android.apps.sshdroid.apk .(如果你懒的下载,给我留言,我会发给你) 2.安装到手机,显示如图: 简单解释一下:一般android系统没有root ...

  5. 【python】 入门 搭建环境

    1.去官网下载包 基本程序编译器 python-2.7.10.msi 集成开发环境 pycharm-community-4.5.2.exe 包管理工具 pip-7.0.3.tar.gz 2.安装 按顺 ...

  6. vs2010旗舰版后,运行调试一个项目时调试不了,提示的是:无法使用“pc”附加到应用程序“webdev.webserver40.exe(PID:2260”

    具体问题描述: vs2010旗舰版后,运行调试一个项目时调试不了,能编译,按ctrl+f5 可以运行,但是就是调试就不行,提示的是:无法使用“pc”附加到应用程序“webdev.webserver40 ...

  7. 总线(BUS)和总线操作

    1.什么是总线? 答:总线是运算部件之间数据流通的公共通道. 2.总线的作用? 答:提高专用信号处理逻辑电路的运算能力和速度. 3.总线与部件之间是怎么连接的? 答:各运算部件和数据寄存器组是通过带控 ...

  8. [转载]iOS面试题总

    转载自:http://blog.sina.com.cn/s/blog_67eb608b0101r6xb.html (2014-06-13 20:23:33) 转载▼ 标签: 转载   crash 原文 ...

  9. webview加载本地html

    //webView.loadUrl("file:///android_asset/index.html"); 加载assets目录中含有的index.html  webView.l ...

  10. 清橙A1363. 水位 - 清华大学2012年信息学优秀高中学子夏令营

    问题描述 有一个正方形的地区,该地区特点鲜明:如果把它等分为N×N个小正方形格子的话,在每个格子内的任意地点的地表高度是相同的,并且是一个0到M之间的整数.正方形地区的外部被无限高的边界包围. 该地区 ...