主席树套树状数组 动态区间第k小

先打上代码以后更新解释

 1 #include <cstdio>
 2 #include <iostream>
 3 #include <algorithm>
 4 #include <cstring>
 5 #include <cmath>
 6 #define REP(i, s, n) for(int i = s; i <= n; i ++)
 7 #define RAP(i, n, s) for(int i = n; i >= s; i --)
 8 #define LOW for(; x; x -= x & (-x))
 9 using namespace std;
10 const int maxn = 100000 + 10;
11 const int Maxn = 100000;
12 const int maxnode = 200 * maxn;
13 int s[maxnode], ls[maxnode], rs[maxnode], A[maxn], root[maxn], Ln, Rn, L[maxn], R[maxn], c[maxn];
14 int n, Q, ms = 0;
15 void update(int x, int& y, int L, int R, int pos, int v){
16     s[y = ++ ms] = s[x] + v;
17     if(L == R) return ;
18     int M = L + R >> 1;
19     ls[y] = ls[x]; rs[y] = rs[x];
20     if(pos <= M) update(ls[x], ls[y], L, M, pos, v);
21     else update(rs[x], rs[y], M + 1, R, pos, v);
22     return ;
23 }
24 void update(int x, int v){
25     for(int i = x; i <= Maxn; i += i & (-i)) update(c[i], c[i], 1, Maxn, A[x], -1); A[x] = v;
26     for(int i = x; i <= Maxn; i += i & (-i)) update(c[i], c[i], 1, Maxn, A[x], 1); return ;
27 }
28 void init(int x, int tp){
29     if(!tp) { L[++ Ln] = root[x]; LOW if(c[x]) L[++ Ln] = c[x]; }
30     else { R[++ Rn] = root[x]; LOW if(c[x]) R[++ Rn] = c[x]; }
31     return ;
32 }
33 int query(int ql, int qr, int k){
34     Ln = Rn = 0; init(qr, 1); init(ql - 1, 0);//0是左
35     int ll = 1, rr = Maxn;
36     while(ll < rr){
37         int Lsum = 0, Rsum = 0, M = ll + rr >> 1;
38         REP(i, 1, Ln) Lsum += s[ls[L[i]]];
39         REP(i, 1, Rn) Rsum += s[ls[R[i]]];
40         int kth = Rsum - Lsum;
41         if(kth >= k){//往左找
42             REP(i, 1, Ln) L[i] = ls[L[i]];
43             REP(i, 1, Rn) R[i] = ls[R[i]];
44             rr = M;
45         }
46         else{//往右找
47             REP(i, 1, Ln) L[i] = rs[L[i]];
48             REP(i, 1, Rn) R[i] = rs[R[i]];
49             ll = M + 1; k -= kth; //看好了二分! 别忘了还要减 Σ( ° △ °|||)︴
50         }
51     }
52     return ll;
53 }
54 inline void read(int &x){
55     x = 0; int sig = 1; char ch = getchar();
56     while(!isdigit(ch)) { if(ch == ‘-‘) sig = -1; ch = getchar(); }
57     while(isdigit(ch)) x = 10 * x + ch - ‘0‘, ch = getchar();
58     x *= sig; return ;
59 }
60 inline void write(int x){
61     if(x == 0) { putchar(‘0‘); return ; }
62     if(x < 0) putchar(‘-‘), x = -x;
63     int len = 0, buf[20];
64     while(x) buf[len ++] = x % 10, x /= 10;
65     RAP(i, len - 1, 0) putchar(buf[i] + ‘0‘); return ;
66 }
67 void init(){
68     read(n); read(Q);
69     REP(i, 1, n) read(A[i]);
70     REP(i, 1, n) update(root[i - 1], root[i], 1, Maxn, A[i], 1);
71     return ;
72 }
73 void work(){
74     int tp, ql, qr, k, x, v;
75     while(Q --){
76         read(tp);
77         if(tp) read(ql), read(qr), read(k), write(query(ql, qr, k) - 1), putchar(‘\n‘);// 减一
78         else read(x), read(v), update(x, v);
79     }
80     return ;
81 }
82 void print(){
83
84     return ;
85 }
86 int main(){
87     init();
88     work();
89     print();
90     return 0;
91 }
时间: 2024-10-08 22:09:12

主席树套树状数组 动态区间第k小的相关文章

POJ 2761 Feed the dogs(树状数组求区间第K大)

题目链接: 戳我 题目大意:Jiajia要为宠物狗,宠物狗按成一排站好(1 < i <= n),第 i 只狗的喜欢程度是 a[i], 之后他会先喂某个区间内第k个 即 n 个数, m个询问,接着是 n个数 接下来 m 行,每行是 l r k即 l 到 r 这个区间第 k 小的数,每个询问输出一个答案,即 a[i] 求区间第k大有很多算法, 详见此博客 [数据结构练习] 求区间第K大数的几种方法 我用的树状数组解法,来自 树状数组从前往后求和,用来解第k大(或小)的数 poj 2985 The

【POJ2104】【整体二分+树状数组】区间第k大

Description You are working for Macrohard company in data structures department. After failing your previous task about key insertion you were asked to write a new data structure that would be able to return quickly k-th order statistics in the array

BZOJ3295 动态逆序对 树套树, 树状数组套线段树(主席树)

Orz黄学长,蒟蒻在黄学长的带领下,通过阅读黄学长的代码!终于会了这道题! 首先我想先说一下这道题的思路(准确来说是黄学长的). 很明显,树状数组应该不用讲吧!关键是内存怎么开,维护一些什么样的数据? 其实我们通过观察,很快可以发现,你维护被删的数比维护所有的数轻松多了(不管是空间上,还是时间上).所以我们就可以从这方面想!(其实我一开始的思路,因为这道题我已经看过很久了,一直想写,毕竟是白书里面的一道例题嘛!一开始,蒟蒻的我是打算这样的用树状数组套权值线段树,并且是维护所有的数,我发现空间不够

ZOJ 2112 Dynamic Rankings(主席树套树状数组+静态主席树)

题意:给定一个区间,求这个区间第k大的数,支持单点修改. 思路:主席树真是个神奇的东西.........速度很快但是也有一个问题就是占用内存的很大,一般来说支持单点修改的主席树套树状数组空间复杂度为O(n*logn*logn), 如果查询较少的话,可以初始的时候用一颗静态主席树,这样空间复杂度可以降为O(n*logn+q*logn*logn),勉强可以过zoj这道题. 这道题看了好久好久才懂...网上题解一般就几句话.......下面是自己的一些理解. 首先静态主席树这个东西其实比较好懂,就是对

【树套树】【树状数组套主席树】

这是你顾第一次写[树套树]!!!!!!!! [原题] 求区间第k小元素,区间可修改 [正解] 如果没有修改的话,就直接写搞个主席树利用前缀和加加减减一下就好了.但是多了个修改,修改以为着从当前修改节点k到往后n-k个树顶所代表的树全部都要修改,这是一件非常操蛋的事情.回想起多年前学数据结构初步的时候,区间批量修改无非就是树状数组or线段树.故我们借用树状数组的轮廓来构建主席树的各树顶. 对树状数组每个节点,我们都当成是主席树的树顶,改树顶所涵盖的区间与树状数组该节点意义相同. [查询]查询区间[

[CDQ分治][树状数组][树套树] Jzoj P3197 K大数查询

Description 有n 个位置和m 个操作.操作有两种,每次操作如果是1 a b c 的形式,表示往第a 个位置到第b 个位置每个位置加入一个数c.如果操作形如2 a b c 的形式,表示询问从第a 个位置到第b 个位置,第c 大的数是多少. Input 在输入文件sequence.in 中,第一行两个数n,m.意义如题目描述.接下来m 行每行形如1 a b c 或者2 a b c 如题目描述. Output 在输出文件sequence.out 中,对于每个询问回答k 大数是多少. Sam

2019南昌网络赛-I. Yukino With Subinterval 线段树套树状数组

TMD...这题卡内存卡的真优秀... 所以以后还是别用主席树的写法...不然怎么死的都不知道... 树套树中,主席树方法开权值线段树...会造成空间的浪费...这道题内存卡的很紧... 由于树套树已经不需要持久化了,直接动态开点就完事了...用主席树方法开过不去,要么超内存,要么越界... 大概思路...这题要求的[L,R]区间内,满足x<=a[i]<=y的连续的段数, 这题大概是个套路题,我们很容易想到,我们把连续的区间变成单点,把一段区间,类似1 1 1 3 5 变成 1 0 0 3 5

树状数组求区间最值

树状数组求区间最值 树状数组(Binary Index Tree)利用二进制的一些性质巧妙的划分区间,是一种编程,时间和空间上都十分理想的求区间和的算法,同样我们可以利用树状数组优美的区间划分方法来求一个序列的最值 约定以 num[]  表示原数组, 以 idx[] 表示索引数组, Lowbit(x)=x&(-x) 树状数组求和时通过构造数组 idx[] 使 idx[k]=sum(num[tk]), tk [k-Lowbit(k)+1,k], 使用同样的方法构造最值索引数组: 以最大值为例, 先

POJ 1195 2维线段树(树套树实现) 树状数组

1: #include <stdio.h> 2: #include <string.h> 3: #include <stdlib.h> 4: #include <algorithm> 5: #include <iostream> 6: using namespace std; 7:   8: #define LL(a) a<<1 9: #define RR(a) a<<1|1 10: const int MaxL = 10