SPOJ--K-query (线段树离线) 离线操作解决一下问题

                              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)
 2 const int MAXN = 3e4+10;
 3 const int MAXQ = 2e5+10;
 4 struct Node{
 5     int L, R, k, idx;
 6     Node (int L = 0, int R = 0, int k = 0, int idx = 0):
 7         L(L), R(R), k(k), idx(idx){}
 8     bool operator < (const Node &rhs)const{
 9         return k < rhs.k;
10     }
11 }Q[MAXQ];
12 int sum[MAXN << 2];
13 void build (int l, int r, int pos){
14     if (l == r){
15         sum[pos] = 1;
16         return;
17     }
18     int mid = (l + r) >> 1;
19     build(l, mid, pos<<1);
20     build(mid+1, r, pos<<1|1);
21     sum[pos] = sum[pos<<1] + sum[pos<<1|1];
22 }
23 void update (int l, int r, int pos, int x, int val){
24     if (l == r){
25         sum[pos] = val;
26         return;
27     }
28     int mid = (l + r) >> 1;
29     if (x <= mid){
30         update(l, mid, pos<<1, x, val);
31     }else{
32         update(mid+1, r, pos<<1|1, x, val);
33     }
34     sum[pos] = sum[pos<<1] + sum[pos<<1|1];
35 }
36 int query (int l, int r, int pos, int ua, int ub){
37     if (ua <= l && ub >= r){
38         return sum[pos];
39     }
40     int mid = (l + r) >> 1;
41     int res = 0;
42     if (ua <mid){
43         res += query(l, mid, pos<<1, ua, ub);
44     }
45     if (ub > mid){
46         res += query(mid+1, r, pos<<1|1, ua, ub);
47     }
48     return res;
49 }
50 int ans[MAXQ], IDX[MAXN], val[MAXN];
51 bool cmp(int i, int j){
52     return val[i] < val[j];
53 }
54 int main() {57     int n, q;
58     while (~ scanf ("%d", &n)){
59         for (int i = 0; i < n; i++){
60             scanf ("%d", val+i);
61             IDX[i] = i;
62         }
63         sort (IDX, IDX+n, cmp);
64         scanf ("%d", &q);
65         for (int i = 0; i < q; i++){
66             int ua, ub, k;
67             scanf ("%d%d%d", &ua, &ub, &k);
68             Q[i] = Node(ua, ub, k, i);
69         }
70         sort (Q, Q+q);
71         build(1, n, 1);
72         int p = 0;
73         for (int i = 0; i < q; i++){
74             while (p < n && val[IDX[p]] <= Q[i].k){
75                 update(1, n, 1, IDX[p]+1, 0);
76                 p++;
77             }
78             ans[Q[i].idx] = query(1, n, 1, Q[i].L, Q[i].R);
79         }
80         for (int i = 0; i < q; i++){
81             printf("%d\n", ans[i]);
82         }
83     }
84     return 0;
85 }
再来看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的值。然后两者比较即可。 代码略。
时间: 2024-10-13 16:14:56

SPOJ--K-query (线段树离线) 离线操作解决一下问题的相关文章

Super Mario(线段树离线区间k值)

以前见过这题,没做出来,知道是离线处理,这次仔细想了下, 首先把出现的高度都map离散化一下,以离散化出来的数目g建树,把每个位置都开俩个vector,一个存以这个位置为L的询问,一个存以这个位置为R的询问. 然后从1-g 进行更新,假如当前i是以第j个区间的开始位置,那么这时就可以询问一下<=p[j].h的个数s,显然这时第J个区间多加的,需要减掉,p[j].sum-=s; 然后更新第i个数,update(a[i],1,g,1);再找到某第k区间是以i结尾的,那么依旧询问一下,得出s,p[k]

线段树+离线 hdu5654 xiaoxin and his watermelon candy

传送门:点击打开链接 题意:一个三元组假设满足j=i+1,k=j+1,ai<=aj<=ak,那么就好的.如今告诉你序列.然后Q次询问.每次询问一个区间[l,r],问区间里有多少个三元组满足要求 思路:刚開始看错题目了,原来三元组是连续3个,这作为bc最后一题也太水了把. . . 先一遍预处理.把连续3个满足条件的找出来,放到还有一个数组里排序去重,用这个数组来给三元组哈希.再扫一遍给三元组在之前那个排序好的数组里二分一下得到下标,大概就是哈希一下,用一个数字来表示. 之后的查询.事实上就是.在

gcd(线段树离线处理)——HDU 4630

对应HDU题目:点击打开链接 No Pain No Game Time Limit: 4000/2000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others) Total Submission(s): 1801    Accepted Submission(s): 770 Problem Description Life is a game,and you lose it,so you suicide. But you can

最简单的问题(重庆市第八届大学生程序设计大赛D) (线段树+离线思想)

考场上的时候直接一脸懵逼了,啥? 区间里面又要求子区间,还TM有上下界? 略加思索后倒是发现没有那么麻烦,因为很容易得出如下结论: 1.对于一个满足条件的区间[L , R],对于他所有的子区间显然也满足条件. 2.一个区间[L , R]的子区间数量(包括自己)为(R-L+1)*(R-L+2)/2 证:因为区间都是连续的,所以显然该区间含有R-L+1个长度为1的子区间,R-L个长度为2的子区间,R-L-1个长度为3的子区间......1个长度为R-L+1的子区间 然后根据等差数列求和公式 Sn =

51nod 1463 找朋友(线段树+离线处理)

http://www.51nod.com/onlineJudge/questionCode.html#!problemId=1463 题意: 思路: 好题! 先对所有查询进行离线处理,按照右区间排序,因为k一共最多只有10个,所有在该区间内的B数组,每次枚举K值,通过这样的方式来得到另外一个B值.但是这样得到的B值它在B数组中的位置必须在当前数的左边.如下图:(j为当前数在B数组中的位置,pos为计算得到的另一个B值在数组中的位置) 这两个数的和记录在pos中,这里pos的位置必须在j的左边,假

HDU4417 线段树 + 离线处理

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4417 , 线段树(或树状数组) + 离线处理 最近看了几道线段树的题都是需要离线处理数据的,正好这块比较手生,就练练了.  这道题主要的地方就是离线处理数据,具体想法: ① 先把所有位置的高度都存下来,然后排序,注意保存下标: ② 把所有询问存下来,然后按照询问的高度进行排序,同注意保存下标: ③ 对于排序后的每次询问的处理:由于每个位置的高度都已经存了下来并且进行了排序,所以可以按照顺序将每个点插

lca 欧拉序+rmq(st) 欧拉序+rmq(线段树) 离线dfs

https://www.luogu.org/problemnew/show/P3379 1.欧拉序+rmq(st) 1 /* 2 在这里,对于一个数,选择最左边的 3 选择任意一个都可以,[left_index,right_index],深度都大于等于这个数的深度 4 */ 5 #include <cstdio> 6 #include <cstdlib> 7 #include <cmath> 8 #include <cstring> 9 #include &

F - One Occurrence CodeForces - 1000F (线段树+离线处理)

You are given an array aa consisting of nn integers, and qq queries to it. ii-th query is denoted by two integers lili and riri. For each query, you have to find any integer that occurs exactly once in the subarray of aa from index lili to index riri

玲珑oj 1117 线段树+离线+离散化,laz大法

1117 - RE:从零开始的异世界生活 Time Limit:1s Memory Limit:256MByte Submissions:438Solved:68 DESCRIPTION 486到了异世界,看到了一群可爱的妹子比如蕾姆啊,艾米莉亚啊,拉姆啊,白鲸啊,怠惰啊等等!有一天膜女告诉486说她的能力可能不能再用了,因为膜女在思考一个数据结构题,没心情管486了.486说我来帮你做,膜女说你很棒棒哦! 给一个集合,最开始为空(不是数学上的集合)五个操作: 1.插入x2.把小于x的数变成x3