K-query

Given a sequence of n numbers a1, a2, ..., an and a number of k- queries. A k-query is a triple (i, j, k) (1 ≤ i ≤ j ≤ n). For each k-query (i, j, k), you have to return the number of elements greater than k in the subsequence ai, ai+1, ..., aj.

Input

  • Line 1: n (1 ≤ n ≤ 30000).
  • Line 2: n numbers a1, a2, ..., an (1 ≤ ai ≤ 109).
  • Line 3: q (1 ≤ q ≤ 200000), the number of k- queries.
  • In the next q lines, each line contains 3 numbers i, j, k representing a k-query (1 ≤ i ≤ j ≤ n, 1 ≤ k ≤ 109).

Output

  • For each k-query (i, j, k), print the number of elements greater than k in the subsequence ai, ai+1, ..., aj in a single line.

Example

Input
5
5 1 2 3 4
3
2 4 1
4 4 4
1 5 2 Output
2
0
3 题意:给定 一个数组, q次询问, 每次询问区间[L, R]内大于k的数字有多少个。 这题算是比较老比较水的题目了, 但是感觉 离线可以处理 很多 大量询问的问题。 其中思想很值得挖掘学习。
比如这题,先考虑线段树,这棵线段树的叶子都是1, 先把 所有询问按k的大小从小到大排序, 然后对于 每个询问可以把 小于当前询问k的数字的位置在线段树里置0,那么结果就是线段树的区间 求和问题来了。 这样Q次询问, 最终所有数字都加进来了 复杂度 并不高 O( N + Q * log N)
 const int MAXN = 3e4+;
const int MAXQ = 2e5+;
struct Node{
int L, R, k, idx;
Node (int L = , int R = , int k = , int idx = ):
L(L), R(R), k(k), idx(idx){}
bool operator < (const Node &rhs)const{
return k < rhs.k;
}
}Q[MAXQ];
int sum[MAXN << ];
void build (int l, int r, int pos){
if (l == r){
sum[pos] = ;
return;
}
int mid = (l + r) >> ;
build(l, mid, pos<<);
build(mid+, r, pos<<|);
sum[pos] = sum[pos<<] + sum[pos<<|];
}
void update (int l, int r, int pos, int x, int val){
if (l == r){
sum[pos] = val;
return;
}
int mid = (l + r) >> ;
if (x <= mid){
update(l, mid, pos<<, x, val);
}else{
update(mid+, r, pos<<|, x, val);
}
sum[pos] = sum[pos<<] + sum[pos<<|];
}
int query (int l, int r, int pos, int ua, int ub){
if (ua <= l && ub >= r){
return sum[pos];
}
int mid = (l + r) >> ;
int res = ;
if (ua <mid){
res += query(l, mid, pos<<, ua, ub);
}
if (ub > mid){
res += query(mid+, r, pos<<|, ua, ub);
}
return res;
}
int ans[MAXQ], IDX[MAXN], val[MAXN];
bool cmp(int i, int j){
return val[i] < val[j];
}
int main() { int n, q;
while (~ scanf ("%d", &n)){
for (int i = ; i < n; i++){
scanf ("%d", val+i);
IDX[i] = i;
}
sort (IDX, IDX+n, cmp);
scanf ("%d", &q);
for (int i = ; i < q; i++){
int ua, ub, k;
scanf ("%d%d%d", &ua, &ub, &k);
Q[i] = Node(ua, ub, k, i);
}
sort (Q, Q+q);
build(, n, );
int p = ;
for (int i = ; i < q; i++){
while (p < n && val[IDX[p]] <= Q[i].k){
update(, n, , IDX[p]+, );
p++;
}
ans[Q[i].idx] = query(, n, , Q[i].L, Q[i].R);
}
for (int i = ; i < q; i++){
printf("%d\n", ans[i]);
}
}
return ;
}
再来看15年编程之美复赛的一道题。

你正在和小冰玩一个猜数字的游戏。小冰首先生成一个长为N的整数序列A1, A2, …, AN。在每一轮游戏中,小冰会给出一个区间范围[L, R],然后你要猜一个数K。如果K在AL, AL+1, …, AR中,那么你获胜。

在尝试了几轮之后,你发现这个游戏太难(无聊)了。小冰决定给你一些提示,你每猜一次,小冰会告诉你K与AL, AL+1, …, AR中最接近的数的绝对差值,即min(|Ai - K|), L ≤ i ≤ R。

也是一个数组,多次询问,每次求区间内与k最接近的数字。 
这题 可以可持久化线段树做, 但是代码量大, 除此之外还可以 离线+线段树, 最接近k的值 要么比k小 要么比k大。
先考虑比k小的时候, 首先 把 所有数字和询问放到一起排序,按值排序, 把询问和数字 分开, 然后 从小到大加入到线段树, 那么对于某次询问[L, R]此时线段树的区间[L, R]最大值就是比k小的最接近的k的值, 同理可以求出比k大的最接近k的值。然后两者比较即可。 代码略。

最新文章

  1. Google开源库-Volley的使用
  2. linux chmod 755
  3. iOS 当请求到的数据是double类型,会失去精准度,并且去掉小数点后的0
  4. 洛谷U4807抽水机[最小生成树]
  5. MySQL 统计信息
  6. (转载)QT中PRO文件写法的详细介绍,很有用,很重要!
  7. 小强HTML5手机发展之路(52)——jquerymobile触摸互动
  8. TypeUtils -- Object 转为 强类型
  9. CodeForces 158B Taxi(贪心)
  10. selenium 相关api操作
  11. 201521123072《java程序设计》第五周学习总结
  12. OKMX6Q在ltib生成的rootfs基础上制作带QT库的根文件系统
  13. 【noip模拟】修长城
  14. comtypes加word 2013批量将pdf转换为doc
  15. Python_queue单项队列
  16. elasticsearch开机启动脚本
  17. 2018-2019-20175205实验二面向对象程序设计《Java开发环境的熟悉》实验报告
  18. 【Teradata】tdlocaledef修改默认日期配置
  19. HTML4到HTML5
  20. mac pro 基本使用

热门文章

  1. bullet HashMap 内存紧密的哈希表
  2. POJ 2044 Weather Forecast
  3. DataTable操作工具类DataTableHelper
  4. 【转】关于Ubuntu的sources.list 的总结
  5. hibernate01ORM的引入
  6. C# 窗口传值的方法
  7. HTML5新增的属性和废除的属性
  8. PHP语言中使用JSON
  9. How to Build CyanogenMod for One X (codename: endeavoru)
  10. MeasureSpec学习