HDU4184 shallot
? 解题记录 ? ? HDU ? ? 线段树分治 ? ? 线性基 ?    2018-05-23 19:33:51    376    0    0

【题目描述】

小苗去市场上买了一捆小葱苗,她突然一时兴起,于是她在每颗小葱苗上写上一个数字,然后把小葱叫过来玩游戏。

每个时刻她会给小葱一颗小葱苗或者是从小葱手里拿走一颗小葱苗,并且让小葱从自己手中的小葱苗里选出一些小葱苗使得选出的小葱苗上的数字的异或和最大。

这种小问题对于小葱来说当然不在话下,但是他的身边没有电脑,于是他打电话给同为Oi选手的你,你能帮帮他吗?

你只需要输出最大的异或和即可,若小葱手中没有小葱苗则输出00

【输入】

第一行一个正整数nn表示总时间;第二行nn个整数a1,a2...ana1,a2...an,若aiai大于00代表给了小葱一颗数字为aiai的小葱苗,否则代表从小葱手中拿走一颗数字为ai−ai的小葱苗。

【输出】

输出共n行,每行一个整数代表第i个时刻的最大异或和。

【输入样例】

  1. 6
  2. 1 2 3 4 -2 -3

【输出样例】

  1. 1
  2. 3
  3. 3
  4. 7
  5. 7
  6. 5

【提示】

N500000,Ai2311N≤500000,Ai≤231−1

学到新操(tao)作(lu)——线段树分治。


考虑对整个时间轴建立线段树。由于每一个数出现多次和出现一次是等价的,我们处理出每一个数出现的时间区间(这一步像我一样懒得化可以用map,233),把每一个区间分为log个线段树内的区间节点(每一个节点下挂一个vector,相当于区间修改操作,类似标记永久化)。这样做之后我们计算答案就只需要遍历线段树,把当前的线性基传给下一层就行了。

  1. #include<cstdio>
  2. #include<cstring>
  3. #include<map>
  4. #include<vector>
  5. #include<algorithm>
  6. using namespace std;
  7. const int stmax = 1 << 30;
  8. const int maxn = 5e5 + 5;
  9. typedef pair<int, int > pii;
  10. int ans[maxn];
  11. pii tmp;
  12.  
  13. struct LNB {
  14. int LB[35];
  15. void init() {memset(LB, 0, sizeof(LB));}
  16. void insert(int u) {
  17. for(register int i = stmax, p = 30; i > 0; i >>= 1, --p) {
  18. if(!(u & i)) continue;
  19. if(!LB[p]) {LB[p] = u; break;}
  20. else u ^= LB[p];
  21. }
  22. }
  23. int qmax(int x) {
  24. for(register int i = 30; i >= 0; --i)
  25. if((x ^ LB[i]) > x) x ^= LB[i];
  26. return x;
  27. }
  28. };
  29.  
  30. map<int, pii > mp;
  31. map<int, pii >::iterator its;
  32. namespace SGT {
  33. struct node {
  34. vector<int > nums;
  35. }tree[maxn << 2];
  36. void add(int l, int r, int tl, int tr, int num, int rt) {
  37. if(tl == l && tr == r)
  38. return tree[rt].nums.push_back(num), void();
  39. int mid = tl + tr >> 1;
  40. if(r <= mid) add(l, r, tl, mid, num, rt << 1);
  41. else if(l > mid) add(l, r, mid + 1, tr, num, rt << 1 | 1);
  42. else {
  43. add(l, mid, tl, mid, num, rt << 1);
  44. add(mid + 1, r, mid + 1, tr, num, rt << 1 | 1);
  45. }
  46. }
  47. void Gans(int l, int r, int rt, LNB now) {
  48. for(register int i = tree[rt].nums.size() - 1; i >= 0; --i)
  49. now.insert(tree[rt].nums[i]);
  50. if(l == r) return ans[l] = now.qmax(0), void();
  51. int mid = l + r >> 1;
  52. Gans(l, mid, rt << 1, now);
  53. Gans(mid + 1, r, rt << 1 | 1, now);
  54. }
  55. }
  56.  
  57. LNB now;
  58. int a[maxn], n, L[maxn], R[maxn], num[maxn], cnt;
  59. int main() {
  60. scanf("%d", &n), now.init();
  61. for(register int i = 1; i <= n; ++i)
  62. scanf("%d", &a[i]);
  63. for(register int i = 1; i <= n; ++i) {
  64. if(a[i] > 0) {
  65. tmp = mp[a[i]];
  66. if(!tmp.first) mp[a[i]] = make_pair(i, 1);
  67. else ++mp[a[i]].second;
  68. } else {
  69. tmp = mp[-a[i]];
  70. if(tmp.second == 1) {
  71. L[++cnt] = tmp.first, R[cnt] = i - 1, num[cnt] = -a[i];
  72. mp.erase(-a[i]);
  73. } else --mp[-a[i]].second;
  74. }
  75. }
  76. for(its = mp.begin(); its != mp.end(); ++its) {
  77. L[++cnt] = its -> second . first;
  78. R[cnt] = n, num[cnt] = its -> first;
  79. }
  80. for(register int i = 1; i <= cnt; ++i)
  81. SGT::add(L[i], R[i], 1, n, num[i], 1);
  82. SGT::Gans(1, n, 1, now);
  83. for(register int i = 1; i <= n; ++i)
  84. printf("%d\n", ans[i]);
  85. return 0;
  86. }

上一篇: 洛谷P3377 【模板】左偏树(可并堆)

下一篇: HDU4117 GRE Words

376 人读过
立即登录, 发表评论.
没有帐号? 立即注册
0 条评论
文档导航