BZOJ3065 带插入区间K小值
Posted HPLarea
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了BZOJ3065 带插入区间K小值相关的知识,希望对你有一定的参考价值。
3065: 带插入区间K小值
Time Limit: 60 Sec Memory Limit: 512 MBDescription
从前有n只跳蚤排成一行做早操,每只跳蚤都有自己的一个弹跳力a[i]。跳蚤国王看着这些跳蚤国欣欣向荣的情景,感到非常高兴。这时跳蚤国王决定理性愉悦一下,查询区间k小值。他每次向它的随从伏特提出这样的问题: 从左往右第x个到第y个跳蚤中,a[i]第k小的值是多少。
这可难不倒伏特,他在脑袋里使用函数式线段树前缀和的方法水掉了跳蚤国王的询问。
这时伏特发现有些跳蚤跳久了弹跳力会有变化,有的会增大,有的会减少。
这可难不倒伏特,他在脑袋里使用树状数组套线段树的方法水掉了跳蚤国王的询问。(orz 主席树)
这时伏特发现有些迟到的跳蚤会插入到这一行的某个位置上,他感到非常生气,因为……他不会做了。
请你帮一帮伏特吧。
快捷版题意:带插入、修改的区间k小值在线查询。
Input
第一行一个正整数n,表示原来有n只跳蚤排成一行做早操。
第二行有n个用空格隔开的非负整数,从左至右代表每只跳蚤的弹跳力。
第三行一个正整数q,表示下面有多少个操作。
下面一共q行,一共三种操作对原序列的操作:(假设此时一共m只跳蚤)
1. Q x y k: 询问从左至右第x只跳蚤到从左至右第y只跳蚤中,弹跳力第k小的跳蚤的弹跳力是多少。
(1 <= x <= y <= m, 1 <= k <= y - x + 1)
2. M x val: 将从左至右第x只跳蚤的弹跳力改为val。
(1 <= x <= m)
3. I x val: 在从左至右第x只跳蚤的前面插入一只弹跳力为val的跳蚤。即插入后从左至右第x只跳蚤是我刚插入的跳蚤。
(1 <= x <= m + 1)
为了体现在线操作,设lastAns为上一次查询的时候程序输出的结果,如果之前没有查询过,则lastAns = 0。
则输入的时候实际是:
Q _x _y _k ------> 表示 Q _x^lastAns _y^lastAns _k^lastAns
M _x _val ------> 表示 M _x^lastAns _val^lastAns
I _x _val ------> 表示 I _x^lastAns _val^lastAns
简单来说就是操作中输入的整数都要异或上一次询问的结果进行解码。
(祝Pascal的同学早日转C++,就不提供pascal版的描述了。)
Output
对于每个询问输出回答,每行一个回答。
Sample Input
10 5 8 28 0 19 2 31 1 22
30
I 6 9
M 1 11
I 8 17
M 1 31
M 6 26
Q 2 7 6
I 23 30
M 31 7
I 22 27
M 26 18
Q 26 17 31
I 5 2
I 18 13
Q 3 3 3
I 27 19
Q 23 23 30
Q 5 13 5
I 3 0
M 15 27
Q 0 28 13
Q 3 29 11
M 2 8
Q 12 5 7
I 30 19
M 11 19
Q 17 8 29
M 29 4
Q 3 0 12
I 7 18
M 29 27
Sample Output
2
31
0
14
15
14
27
15
14
HINT
此题作为一个小小的研究来搞吧~做法有很多~不知道这题究竟有多少种做法。
请自觉O(log^2n),我故意卡块状链表,块链A了的请受我深情一拜……
A掉的同学请在Discuss里面简要说下自己的做法吧~
原序列长度 <= 35000
插入个数 <= 35000,修改个数 <= 70000,查询个数 <= 70000 ,0 <= 每时每刻的权值 <= 70000
由于是OJ上的题,所以数据无梯度。为了防止卡OJ,本题只有4组数据。
这是一道SB数据结构,替罪羊套权值线段树可以解决,膜拜块链与划分树神犇Orz
inline bool isbad(int rt) { return sz[rt] * alpha < max(sz[t[rt].l], sz[t[rt].r]); }
void dfs_part(int rt, int pos) { if (pos == 0) return ; if (pos == sz[t[rt].l]) { p[++pcnt] = Pnode(1, root[t[rt].l]); } else if (pos > sz[t[rt].l]) { p[++pcnt] = Pnode(1, root[rt]); p[++pcnt] = Pnode(-1, root[t[rt].r]); dfs_part(t[rt].r, pos - sz[t[rt].l] - 1); } else { dfs_part(t[rt].l, pos); } }
然后就没有然后了,插入询问都是\( n\log^{2}n \)注意询问时先提取所有区间然后再直接二分
1 #include<bits/stdc++.h> 2 using namespace std; 3 template <class _T> inline void read(_T &_x) { 4 int _t; bool flag = false; 5 while ((_t = getchar()) != ‘-‘ && (_t < ‘0‘ || _t > ‘9‘)) ; 6 if (_t == ‘-‘) _t = getchar(), flag = true; _x = _t - ‘0‘; 7 while ((_t = getchar()) >= ‘0‘ && _t <= ‘9‘) _x = _x * 10 + _t - ‘0‘; 8 if (flag) _x = -_x; 9 } 10 const int maxn = 70010; 11 struct Tnode { 12 int v, l, r; 13 }; 14 namespace T { 15 Tnode t[maxn * 400]; 16 int st[maxn * 400], top, tot; 17 inline int newnode() { 18 if (!top) st[top++] = ++tot; 19 int cur = st[--top]; 20 t[cur].v = t[cur].l = t[cur].r = 0; 21 return cur; 22 } 23 void remove(int rt) { 24 if (!rt) return ; 25 remove(t[rt].l), remove(t[rt].r); 26 st[top++] = rt; 27 } 28 int merge(int a, int b) { 29 if (!a && !b) return 0; 30 int cur = newnode(); 31 t[cur].v = t[a].v + t[b].v; 32 t[cur].l = merge(t[a].l, t[b].l); 33 t[cur].r = merge(t[a].r, t[b].r); 34 return cur; 35 } 36 void insert(int &rt, int l, int r, int pos, int val) { 37 if (!rt) rt = newnode(); t[rt].v += val; 38 if (l == r) return ; 39 int mid = (l + r) >> 1; 40 if (pos <= mid) insert(t[rt].l, l, mid, pos, val); 41 else insert(t[rt].r, mid + 1, r, pos, val); 42 if (!t[rt].v) remove(rt), rt = 0; 43 } 44 } 45 namespace S { 46 const double alpha = 0.7; 47 Tnode t[maxn * 2]; 48 int st[maxn * 2], top, tot; 49 int root[maxn * 2], sz[maxn * 2]; //root for segtree 50 int Root, v[maxn * 2], cnt, badroot; //Root of Scapegoat 51 inline int newnode() { 52 if (!top) st[top++] = ++tot; 53 int cur = st[--top]; 54 t[cur].v = t[cur].l = t[cur].r = 0; 55 return cur; 56 } 57 void remove(int rt) { 58 if (!rt) return ; 59 remove(t[rt].l), remove(t[rt].r); 60 T::remove(root[rt]); 61 st[top++] = rt; 62 } 63 inline bool isbad(int rt) { 64 return sz[rt] * alpha < max(sz[t[rt].l], sz[t[rt].r]); 65 } 66 void print(int rt) { 67 if (!rt) return ; 68 print(t[rt].l); 69 cout << t[rt].v << ‘ ‘ ; 70 print(t[rt].r); 71 } 72 void Print() { 73 cout << "Seq: " ; print(Root); 74 cout << endl; 75 } 76 void insert(int &rt, int pos, int val) { // insert val after pos 77 if (!rt) rt = newnode(), sz[rt] = 0, t[rt].v = val; 78 ++sz[rt]; 79 T::insert(root[rt], 0, maxn, val, 1); 80 if (sz[rt] != 1) { 81 if (pos <= sz[t[rt].l]) insert(t[rt].l, pos, val); 82 else insert(t[rt].r, pos - sz[t[rt].l] - 1, val); 83 if (isbad(rt)) badroot = rt; 84 } 85 } 86 void dfs_node(int rt) { 87 if (!rt) return ; 88 dfs_node(t[rt].l); 89 v[++cnt] = t[rt].v; 90 dfs_node(t[rt].r); 91 } 92 void build(int &rt, int l, int r) { 93 rt = newnode(); 94 int mid = (l + r) >> 1; 95 t[rt].v = v[mid], sz[rt] = r - l + 1; 96 if (l < mid) build(t[rt].l, l, mid - 1); 97 if (mid < r) build(t[rt].r, mid + 1, r); 98 root[rt] = T::merge(root[t[rt].l], root[t[rt].r]); 99 T::insert(root[rt], 0, maxn, t[rt].v, 1); 100 } 101 void rebuild(int &rt) { 102 cnt = 0, dfs_node(rt); 103 remove(rt); 104 build(rt, 1, cnt); 105 } 106 void init(int n) { 107 for (int i = 1; i <= n; ++i) read(v[i]); 108 build(Root, 1, n); 109 } 110 void Insert(int pos, int val) { // insert before pos & rebuild 111 //printf("Insert %d before position %d\n", val, pos); 112 badroot = 0; 113 insert(Root, pos - 1, val); 114 if (badroot) rebuild(badroot); 115 } 116 int change(int &rt, int pos, int val) { 117 int ret = -1; 118 if (pos == sz[t[rt].l] + 1) { 119 ret = t[rt].v, t[rt].v = val; 120 goto Modify_part; 121 } 122 if (pos <= sz[t[rt].l]) ret = change(t[rt].l, pos, val); 123 else ret = change(t[rt].r, pos - sz[t[rt].l] - 1, val); 124 Modify_part:T::insert(root[rt], 0, maxn, val, 1), 125 T::insert(root[rt], 0, maxn, ret, -1); 126 return ret; 127 } 128 void Change(int pos, int val) { 129 //printf("Change position %d‘s value to %d\n", pos, val); 130 change(Root, pos, val); 131 } 132 struct Pnode { 133 int v, rt; 134 Pnode() {} 135 Pnode(int a, int b):v(a), rt(b) {} 136 }p[maxn * 2]; 137 int pcnt; 138 void dfs_part(int rt, int pos) { 139 if (pos == 0) return ; 140 if (pos == sz[t[rt].l]) { 141 p[++pcnt] = Pnode(1, root[t[rt].l]); 142 } else if (pos > sz[t[rt].l]) { 143 p[++pcnt] = Pnode(1, root[rt]); 144 p[++pcnt] = Pnode(-1, root[t[rt].r]); 145 dfs_part(t[rt].r, pos - sz[t[rt].l] - 1); 146 } else { 147 dfs_part(t[rt].l, pos); 148 } 149 } 150 int Query(int l, int r, int k) { 151 //printf("Query %d%s smallest in range [%d, %d]\n", k, k%10 == 1 ? "st" : (k%10 == 2 ? "nd" : (k%10 == 3 ? "rd" : "th")), l, r); 152 pcnt = 0; 153 dfs_part(Root, l - 1); 154 for (int i = 1; i <= pcnt; ++i) p[i].v = -p[i].v; 155 dfs_part(Root, r); 156 int L = 0, R = maxn, mid, totv; 157 while (L < R) { 158 mid = (L + R) >> 1, totv = 0; 159 for (int i = 1; i <= pcnt; ++i) totv += p[i].v * T::t[T::t[p[i].rt].l].v; 160 //cout << mid << ‘ ‘ << tot << endl; 161 if (totv >= k) { 162 for (int i = 1; i <= pcnt; ++i) p[i].rt = T::t[p[i].rt].l; 163 R = mid; 164 } else { 165 for (int i = 1; i <= pcnt; ++i) p[i].rt = T::t[p[i].rt].r; 166 k -= totv, L = mid + 1; 167 } 168 } 169 return L; 170 } 171 } 172 using S::Print; 173 int n, q; 174 int main() { 175 //freopen("3065.in", "r", stdin); 176 //freopen("3065.out", "w", stdout); 177 read(n); 178 S::init(n); 179 //Print(); 180 read(q); 181 char op[20]; 182 int lastans = 0; 183 for (int i = 1, a, b, c; i <= q; ++i) { 184 scanf("%s", op); 185 switch (op[0]) { 186 case ‘Q‘: 187 read(a), read(b), read(c); 188 a ^= lastans, b ^= lastans, c ^= lastans; 189 printf("%d\n", lastans = S::Query(a, b, c)); 190 break; 191 case ‘M‘: 192 read(a), read(b); 193 a ^= lastans, b ^= lastans; 194 S::Change(a, b); 195 break; 196 case ‘I‘: 197 read(a), read(b); 198 a ^= lastans, b ^= lastans; 199 S::Insert(a, b); 200 break; 201 } 202 //Print(); 203 } 204 return 0; 205 }
以上是关于BZOJ3065 带插入区间K小值的主要内容,如果未能解决你的问题,请参考以下文章