BZOJ3217 ALOEXT
3217: ALOEXT
Description
taorunz平时最喜欢的东西就是可移动存储器了……只要看到别人的可移动存储器,他总是用尽一切办法把它里面的东西弄到手。
突然有一天,taorunz来到了一个密室,里面放着一排可移动存储器,存储器里有非常珍贵的OI资料……不过比较特殊的是,每个存储器上都写着一个非负整数。taorunz很高兴,要把所有的存储器都拿走(taorunz的智商高达500,他一旦弄走了这里的所有存储器,在不久到来的AHOI和NOI中……你懂的)。不过这时有一个声音传来:“你只能拿走这里的一个存储器,而且还不能直接拿,你需要指定一段区间[l, r],满足l<r,然后在第l个和第r个存储器之间选一个拿走,你能获得的知识增加量等于区间[l, r]中所有存储器上写的整数的次大值与你拿走的这个存储器上写的整数作按位异或运算的结果。”
问题是,这里的可移动存储器数量太多,而且,它们还在不断地发生变化,有时候天上会掉下来一个新的存储器,并插入到这一排存储器中,有时候某个存储器会不明原因消失,有时候某个存储器上写的整数变化了。taorunz虽然智商很高,但也无法应对如此快的变化,他指定了许多段区间,让你帮他找出如果在这个区间中拿走存储器,他能获得的最多的知识是多少。
Input
第一行两个整数N、M,表示一开始的存储器数和后面发生的事件数。
第二行N个非负整数,表示一开始从左到右每个存储器上写的数字。注意,存储器从0开始编号,也就是最左边的存储器是第0个。
接下来M行,每行描述一个事件,有4种可能的事件。
(1)I x y:表示天上掉下来一个写着数字y的存储器,并插入到原来的第x个存储器之前,如果x等于原来存储器的个数,则插入到末尾;
(2)[D] x:表示第x个存储器消失;
(3)C x y:表示第x个存储器上写的数字变为y;
(4)F l r:表示taorunz指定区间[l, r],让你告诉他最多能获得多少知识。
注意,本题强制在线,也就是事件中出现的所有数字都进行了加密,数字s表示的真实值是
对于I、[D]、C事件中的x及F事件中的l、r:(s+last_ans) mod n0;
对于I、C事件中的y:(s+last_ans) mod 1048576。
其中n0为目前存储器个数,last_ans为上一个F事件的结果,如果前面尚未发生F事件,则last_ans=0。
Output
对于每个F事件,输出结果。
Sample Input
2 6 3 8 7
F 1 4
I 2 1048565
I 0 1048566
D 3
F 3 0
I 3 1048569
D 5
C 1 1048570
F 1 2
F 2 1
Sample Output
7
4
7
HINT
Source
又是一道卡了3天的神犇树套树。
首先,样例有问题,[D]在测试数据里是D。
好吧,替罪羊套trie,听着就sb,写起来也sb的题,替罪羊爱咋写咋写
删除是本题唯一的难点,不能直接删,删了的话替罪羊就会开始疯狂重构,直接GG,打个标记,咱当这点不存在。
所以记录一个sz,一个max_sz,sz就是还被删除的点的个数,max_sz是总和,序列找点用sz,平时的sz + 1等要改成sz + (!t[rt].del),替罪羊判断是否重构用max_sz,重构也不要删掉打了标记的点。网上有大佬用类似线段树的方式建替罪羊,把序列全部建在叶子节点,这样就避免的删除带来的困扰,但他的代码在我对拍的时候GG了,大家观摩思想就好,别抄代码。。。
然后就没有然后了,题目有点卡,alpha推荐0.75。
ACcode:
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 typedef long long LL; 11 const int DEP = 20; 12 const int maxv = 200010; 13 const int MOD = 1048576; 14 namespace T { 15 const int maxt = maxv * DEP * 8; 16 struct Tnode { 17 int v, ch[2]; 18 }t[maxt]; 19 int st[maxt], top, tot; 20 inline int newnode() { 21 if (!top) st[top++] = ++tot; 22 int cur = st[--top]; 23 t[cur].v = t[cur].ch[0] = t[cur].ch[1] = 0; 24 return cur; 25 } 26 void reclaim(int rt) { 27 if (!rt) return ; 28 reclaim(t[rt].ch[0]), reclaim(t[rt].ch[1]); 29 st[top++] = rt; 30 } 31 void insert(int &rt, int val, int dep) { 32 if (!rt) rt = newnode(); ++t[rt].v; 33 if (dep < 0) return ; 34 insert(t[rt].ch[(val>>dep)&1], val, dep - 1); 35 } 36 void remove(int &rt, int val, int dep) { 37 --t[rt].v; 38 if (!t[rt].v) { 39 reclaim(rt), rt = 0; 40 return ; 41 } 42 if (dep < 0) return ; 43 remove(t[rt].ch[(val>>dep)&1], val, dep - 1); 44 } 45 int merge(int a, int b) { 46 if (!a && !b) return 0; 47 int rt = newnode(); 48 t[rt].v = t[a].v + t[b].v; 49 t[rt].ch[0] = merge(t[a].ch[0], t[b].ch[0]); 50 t[rt].ch[1] = merge(t[a].ch[1], t[b].ch[1]); 51 return rt; 52 } 53 } 54 namespace S { //scapegoat 55 const double alpha = 0.75; 56 struct Snode { 57 int v, l, r; 58 int sz, max_sz, root; 59 bool del; 60 }t[maxv]; 61 int st[maxv], top, tot; 62 int Root; 63 void print(int rt) { 64 if (!rt) return ; 65 //putchar('['); 66 print(t[rt].l); 67 if (!t[rt].del) printf("%d ", t[rt].v); 68 print(t[rt].r); 69 //putchar(']'); 70 } 71 inline void Print() { 72 cout << "Seq: "; 73 print(Root); 74 cout << endl; 75 } 76 inline bool isbad(int rt) { 77 return t[rt].max_sz * alpha < max(t[t[rt].l].max_sz, t[t[rt].r].max_sz); 78 } 79 inline int newnode(int val) { 80 if (!top) st[top++] = ++tot; 81 int cur = st[--top]; 82 t[cur].v = val; 83 t[cur].root = t[cur].l = t[cur].r = t[cur].del = 0; 84 t[cur].sz = t[cur].max_sz = 0; 85 return cur; 86 } 87 void reclaim(int rt) { 88 if (!rt) return ; 89 reclaim(t[rt].l), reclaim(t[rt].r); 90 T::reclaim(t[rt].root); 91 st[top++] = rt; 92 } 93 int v0[maxv], cnt; 94 void dfs_node(int rt) { 95 if (!rt) return ; 96 dfs_node(t[rt].l); 97 v0[++cnt] = t[rt].del ? -1 : t[rt].v; 98 dfs_node(t[rt].r); 99 } 100 void build(int &rt, int l, int r) { 101 int mid = (l + r) >> 1; 102 rt = newnode(v0[mid]); 103 if (t[rt].v == -1) t[rt].del = true; 104 if (l < mid) build(t[rt].l, l, mid - 1); 105 if (mid < r) build(t[rt].r, mid + 1, r); 106 t[rt].sz = t[t[rt].l].sz + t[t[rt].r].sz + (!t[rt].del); 107 t[rt].max_sz = t[t[rt].l].max_sz + t[t[rt].r].max_sz + 1; 108 t[rt].root = T::merge(t[t[rt].l].root, t[t[rt].r].root); 109 if (!t[rt].del) T::insert(t[rt].root, t[rt].v, DEP - 1); 110 } 111 void rebuild(int &rt) { 112 cnt = 0, dfs_node(rt); 113 reclaim(rt); 114 build(rt, 1, cnt); 115 } 116 int badroot; 117 void insert(int &rt, int pos, int val) { 118 if (!rt) { 119 rt = newnode(val); 120 ++t[rt].sz, ++t[rt].max_sz; 121 T::insert(t[rt].root, val, DEP - 1); 122 return ; 123 } 124 ++t[rt].sz, ++t[rt].max_sz; 125 T::insert(t[rt].root, val, DEP - 1); 126 if (pos <= t[t[rt].l].sz + (!t[rt].del)) insert(t[rt].l, pos, val); 127 else insert(t[rt].r, pos - t[t[rt].l].sz - (!t[rt].del), val); 128 if (isbad(rt)) badroot = rt; 129 } 130 int change(int rt, int pos, int val) { 131 int ret = 0; 132 if (!t[rt].del && pos == t[t[rt].l].sz + 1) { 133 ret = t[rt].v, t[rt].v = val; 134 T::insert(t[rt].root, val, DEP - 1), 135 T::remove(t[rt].root, ret, DEP - 1); 136 return ret; 137 } 138 if (pos <= t[t[rt].l].sz) ret = change(t[rt].l, pos, val); 139 else ret = change(t[rt].r, pos - t[t[rt].l].sz - (!t[rt].del), val); 140 T::insert(t[rt].root, val, DEP - 1), 141 T::remove(t[rt].root, ret, DEP - 1); 142 return ret; 143 } 144 int remove(int rt, int pos) { 145 --t[rt].sz; 146 if (!t[rt].del && pos == t[t[rt].l].sz + 1) { 147 t[rt].del = true; 148 T::remove(t[rt].root, t[rt].v, DEP - 1); 149 return t[rt].v; 150 } 151 int ret = 0; 152 if (pos <= t[t[rt].l].sz) ret = remove(t[rt].l, pos); 153 else ret = remove(t[rt].r, pos - t[t[rt].l].sz - (!t[rt].del)); 154 T::remove(t[rt].root, ret, DEP - 1); 155 return ret; 156 } 157 inline void Init(int n) { 158 for (int i = 1; i <= n; ++i) read(v0[i]); 159 build(Root, 1, n); 160 } 161 inline void Insert(int pos, int val) { 162 //printf("Insert %d before position %d\n", val, pos); 163 badroot = 0; 164 insert(Root, pos + 1, val); 165 if (badroot) rebuild(badroot); 166 } 167 inline void Change(int pos, int val) { 168 //printf("Change position %d to %d\n", pos, val); 169 change(Root, pos + 1, val); 170 } 171 inline void Delete(int pos) { 172 //printf("Delete position %d\n", pos); 173 remove(Root, pos + 1); 174 } 175 struct Qnode { 176 int v, rt; 177 Qnode(int a = 0, int b = 0):v(a), rt(b) {} 178 }p[maxv], ori[maxv]; 179 int pcnt; 180 void dfs_part(int rt, int pos) { 181 if (!pos) return ; 182 if (pos == t[t[rt].l].sz) { 183 p[++pcnt] = Qnode(1, t[t[rt].l].root); 184 } else if (pos < t[t[rt].l].sz) { 185 dfs_part(t[rt].l, pos); 186 } else { 187 p[++pcnt] = Qnode(1, t[rt].root); 188 p[++pcnt] = Qnode(-1, t[t[rt].r].root); 189 dfs_part(t[rt].r, pos - t[t[rt].l].sz - (!t[rt].del)); 190 } 191 } 192 inline int Query(int l, int r) { 193 ++l, ++r; 194 //printf("Query in range [%d, %d]\n", l, r); 195 pcnt = 0; 196 dfs_part(Root, l - 1); 197 for (int i = 1; i <= pcnt; ++i) p[i].v = -p[i].v; 198 dfs_part(Root, r); 199 memcpy(ori + 1, p + 1, pcnt * sizeof(Qnode)); 200 int ret = 0, k = 2; 201 LL totl, totr; 202 int L = 0, R = (1<<DEP) - 1; 203 for (int dep = DEP - 1; dep >= 0; --dep) { 204 totl = totr = 0; 205 for (int i = 1; i <= pcnt; ++i) { 206 //totl += p[i].v * T::t[T::t[p[i].rt].ch[0]].v; 207 totr += p[i].v * T::t[T::t[p[i].rt].ch[1]].v; 208 } 209 //printf("%d - %d & %d - %d: %I64d %I64d\n", L, L + (1<<dep) - 1, L + (1 << dep), R, totl, totr); 210 if (totr < k) { 211 k -= (int)totr; 212 R -= 1 << dep; 213 for (int i = 1; i <= pcnt; ++i) 214 p[i].rt = T::t[p[i].rt].ch[0]; 215 } else { 216 ret += 1 << dep; 217 L += 1 << dep; 218 for (int i = 1; i <= pcnt; ++i) 219 p[i].rt = T::t[p[i].rt].ch[1]; 220 } 221 } 222 //cout << ret << endl; 223 memcpy(p + 1, ori + 1, pcnt * sizeof(Qnode)); 224 int ans = 0; 225 for (int dep = DEP - 1; dep >= 0; --dep) { 226 totl = 0, totr = 0; 227 for (int i = 1; i <= pcnt; ++i) { 228 totl += p[i].v * T::t[T::t[p[i].rt].ch[0]].v; 229 totr += p[i].v * T::t[T::t[p[i].rt].ch[1]].v; 230 } 231 if (!totl || (totr && ((ret>>dep)&1) == 0)) { 232 ans += 1 << dep; 233 for (int i = 1; i <= pcnt; ++i) 234 p[i].rt = T::t[p[i].rt].ch[1]; 235 } else { 236 for (int i = 1; i <= pcnt; ++i) 237 p[i].rt = T::t[p[i].rt].ch[0]; 238 } 239 } 240 //cout << ans << endl; 241 return ans ^ ret; 242 } 243 } 244 int main() { 245 //freopen("3217.in", "r", stdin); 246 //freopen("3217.out", "w", stdout); 247 int n, m; 248 read(n), read(m); 249 S::Init(n); 250 char op[20]; 251 int lastans = 0, n0 = n; 252 for (int i = 1, a, b; i <= m; ++i) { 253 //S::Print(); 254 scanf("%s", op); 255 switch (op[0]) { 256 case 'I': 257 read(a), read(b); 258 a = (a + lastans) % n0; 259 b = (b + lastans) % MOD; 260 S::Insert(a, b); 261 ++n0; 262 break; 263 case 'D': 264 read(a); 265 a = (a + lastans) % n0; 266 S::Delete(a); 267 --n0; 268 break; 269 case 'C': 270 read(a), read(b); 271 a = (a + lastans) % n0; 272 b = (b + lastans) % MOD; 273 S::Change(a, b); 274 break; 275 case 'F': 276 read(a), read(b); 277 a = (a + lastans) % n0; 278 b = (b + lastans) % n0; 279 printf("%d\n", lastans = S::Query(a, b)); 280 break; 281 } 282 } 283 return 0; 284 }
良心数据生成器:
#include<bits/stdc++.h> using namespace std; int main () { freopen("test.in", "w", stdout); srand(time(NULL)); int n = 5, m = 5; cout << n << ' ' << m << endl; for (int i = 1; i <= n; ++i) { cout << rand() % 100 << ' '; } cout << endl; int n0 = n; for (int i = 1, a, b; i <= m; ++i) { int op = rand() % 4; while (n0 <= 2 && op == 1) op = rand() % 4; switch (op) { case 0: a = rand() % n0; b = rand() % 100; printf("I %d %d\n", a, b); ++n0; break; case 1: a = rand() % n0; printf("D %d\n", a); --n0; break; case 2: a = rand() % n0; b = rand() % 100; printf("C %d %d\n", a, b); break; case 3: a = rand() % (n0 - 1); b = a + rand() % (n0 - a - 1) + 1; printf("F %d %d\n", a, b); break; } } return 0; }
作者:HPL 出处:https://www.cnblogs.com/akhpl/ 感谢您的阅读,如果您觉得阅读本文对您有帮助,请点一下“推荐”按钮。本文由CC BY-NC-ND 2.5授权,欢迎读者转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,谢谢。