好几天之前做的题目了,一直想写一下博客也没腾出时间来,今天赶紧把坑给填上呼呼呼~

  这道题首先如果只考虑每个商店中没有时间限制的物品时,我们只需要使用一棵可持久化trie树来维护区间内的异或最大值即可,这样我们可以把两部分的问题分离开来。

  之后我们再考虑有时间限制与编号限制的情况下,该怎样做?无脑做法线段树套trie,直接在对应的区间trie树上贪心,如果该条边的最后更新时间在允许的范围内,说明可以走这条边。虽然这样也可以卡过去(主要在于卡空间),但我们来介绍一种更加妙妙的线段树分治做法。其实我感觉在这题的体现上就是离线版树套树?机房大佬貌似不认可,但我确实是这样觉得哒。

  我们考虑在线椴树上的一次区间查询,实际上是将查询的区间分成了log个已经处理好的小区间,分别查询之后再合并达到最终的答案。那么我们可以模拟这个在线段树上分裂区间的操作:

  1.如果当前处理的区间(l,r)完全包含于询问区间,我们将这个询问的区间在这一层进行处理。(这样的询问均不再下传,跳过后续步骤)

  2.如果询问的区间有涉及(l,mid)的范围,递归左区间处理。

  3.如果询问的区间有涉及(mid+1,r)的范围,递归右区间处理。

  (本题分治的区间表示时间的范围,可持久化trie负责处理编号的限制)。

  这样的复杂度是多少?我们可以分处理trie树与查询的两个方面来分析。处理trie树时,我们插入一个值是log的复杂度,而包含一个修改的总分治区间数也是log个,所以是\(O(nlog^{2}n)\)的复杂度。查询也是log的复杂度,一个查询最多被分别查询 log 次。所以复杂度依然是 \(O(nlog^{2}n)\) 的。

  1. #include <bits/stdc++.h>
  2. using namespace std;
  3. #define maxn 1000000
  4. int n, m, sz, qt, nt, tot, cnt, timer;
  5. int ans[maxn], sum[maxn * ], id[maxn], q[maxn];
  6. int bit[], ch[maxn * ][], num[maxn], root[maxn];
  7.  
  8. int read()
  9. {
  10. int x = , k = ;
  11. char c; c = getchar();
  12. while(c < '' || c > '') { if(c == '-') k = -; c = getchar(); }
  13. while(c >= '' && c <= '') x = x * + c - '', c = getchar();
  14. return x * k;
  15. }
  16.  
  17. struct ques
  18. {
  19. int l, r, s, t, x;
  20. }Q[maxn];
  21.  
  22. struct modify
  23. {
  24. int id, val, t;
  25. friend bool operator <(const modify& a, const modify& b)
  26. { return a.id < b.id; }
  27. }P[maxn], ql[maxn], qr[maxn];
  28.  
  29. void Ins(int now, int last, int x, int val)
  30. {
  31. if(x < ) return;
  32. bool t = (bit[x] & val);
  33. ch[now][!t] = ch[last][!t]; ch[now][t] = ++ sz;
  34. sum[ch[now][t]] = sum[ch[last][t]] + ;
  35. Ins(ch[now][t], ch[last][t], x - , val);
  36. }
  37.  
  38. int Query(int l, int r, int x, int val)
  39. {
  40. if(l > r || x < ) return ;
  41. int ans = ; bool t = val & bit[x];
  42. if(sum[ch[r][!t]] - sum[ch[l][!t]])
  43. ans = (bit[x] + Query(ch[l][!t], ch[r][!t], x - , val));
  44. else ans = Query(ch[l][t], ch[r][t], x - , val);
  45. return ans;
  46. }
  47.  
  48. int Check(int v)
  49. {
  50. int l = , r = nt, ret = ;
  51. while(l <= r)
  52. {
  53. int mid = (l + r) >> ;
  54. if(num[mid] <= v) ret = mid, l = mid + ;
  55. else r = mid - ;
  56. }
  57. return ret;
  58. }
  59.  
  60. void Work(int l, int r)
  61. {
  62. sz = , nt = ;
  63. for(int i = l; i <= r; i ++)
  64. {
  65. nt ++; root[nt] = ++ sz;
  66. Ins(root[nt], root[nt - ], , P[i].val);
  67. num[nt] = P[i].id;
  68. }
  69. for(int i = ; i <= qt; i ++)
  70. {
  71. int l = Check(Q[q[i]].l - ), r = Check(Q[q[i]].r);
  72. ans[q[i]] = max(ans[q[i]], Query(root[l], root[r], , Q[q[i]].x));
  73. }
  74. }
  75.  
  76. void Divide(int l, int r, int L, int R, int pres)
  77. {
  78. if(l > r || !pres) return;
  79. int mid = (L + R) >> ; qt = ;
  80. for(int i = ; i <= pres; i ++)
  81. if(Q[id[i]].s <= L && R <= Q[id[i]].t) q[++ qt] = id[i];
  82. Work(l, r); if(L == R) return;
  83. int ll = , rr = ;
  84. for(int i = l; i <= r; i ++)
  85. {
  86. if(P[i].t <= mid) ql[++ ll] = P[i];
  87. else qr[++ rr] = P[i];
  88. }
  89. for(int i = ; i <= ll; i ++) P[i + l - ] = ql[i];
  90. for(int i = ; i <= rr; i ++) P[i + l + ll - ] = qr[i];
  91.  
  92. int ind = ;
  93. for(int i = ; i <= pres; i ++)
  94. {
  95. if(Q[id[i]].s <= L && R <= Q[id[i]].t) continue;
  96. if(Q[id[i]].s <= mid) swap(id[i], id[++ ind]);
  97. }
  98. Divide(l, l + ll - , L, mid, ind);
  99. ind = ;
  100. for(int i = ; i <= pres; i ++)
  101. {
  102. if(Q[id[i]].s <= L && R <= Q[id[i]].t) continue;
  103. if(Q[id[i]].t > mid) swap(id[i], id[++ ind]);
  104. }
  105. Divide(l + ll, r, mid + , R, ind);
  106. }
  107.  
  108. int main()
  109. {
  110. bit[] = ; for(int i = ; i <= ; i ++) bit[i] = bit[i - ] << ;
  111. n = read(), m = read();
  112. for(int i = ; i <= n; i ++) root[i] = ++ sz, Ins(root[i], root[i - ], , read());
  113. for(int i = ; i <= m; i ++)
  114. {
  115. int opt = read();
  116. if(!opt)
  117. {
  118. ++ timer; P[++ tot].id = read();
  119. P[tot].val = read(); P[tot].t = timer;
  120. }
  121. else
  122. {
  123. Q[++ cnt].l = read(); Q[cnt].r = read();
  124. Q[cnt].x = read(); int d = read();
  125. Q[cnt].s = max(timer - d, ) + ; Q[cnt].t = timer;
  126. ans[cnt] = Query(root[Q[cnt].l - ], root[Q[cnt].r], , Q[cnt].x);
  127. }
  128. }
  129. sort(P + , P + + tot);
  130. for(int i = ; i <= cnt; i ++) id[i] = i;
  131. Divide(, tot, , timer, cnt);
  132. for(int i = ; i <= cnt; i ++) printf("%d\n", ans[i]);
  133. return ;
  134. }

【题解】FJOI2015火星商店问题的更多相关文章

  1. 【题解】P4585 [FJOI2015]火星商店问题(线段树套Trie树)

    [题解]P4585 [FJOI2015]火星商店问题(线段树套Trie树) 语文没学好不要写省选题面!!!! 题目大意: 有\(n\)个集合,每个集合有个任意时刻都可用的初始元素.现在有\(m\)个操 ...

  2. 【LG4585】[FJOI2015]火星商店问题

    [LG4585][FJOI2015]火星商店问题 题面 bzoj权限题 洛谷 \(Notice:\) 关于题面的几个比较坑的地方: "一天"不是一个操作,而是有0操作就相当于一天开 ...

  3. [FJOI2015]火星商店问题

    [FJOI2015]火星商店问题 神仙线段树分治...不过我不会. 这题用线段树套可持久化Trie还是能写的. 常数有点大,洛谷垫底水平. // luogu-judger-enable-o2 #inc ...

  4. 洛谷 P4585 [FJOI2015]火星商店问题 解题报告

    P4585 [FJOI2015]火星商店问题 题目描述 火星上的一条商业街里按照商店的编号\(1,2,\dots,n\) ,依次排列着\(n\)个商店.商店里出售的琳琅满目的商品中,每种商品都用一个非 ...

  5. [FJOI2015]火星商店问题(线段树分治,可持久化,Trie树)

    [FJOI2015]火星商店问题 前天考了到线段树分治模板题,全场都切了,就我不会QAQ 于是切题无数的Tyher巨巨就告诉我:"你可以去看看火星商店问题,看了你就会了." 第一道 ...

  6. [FJOI2015]火星商店问题(分治+可持久化)

    题目描述 火星上的一条商业街里按照商店的编号1,2 ,…,n ,依次排列着n个商店.商店里出售的琳琅满目的商品中,每种商品都用一个非负整数val来标价.每个商店每天都有可能进一些新商品,其标价可能与已 ...

  7. BZOJ4137 & 洛谷4585:[FJOI2015]火星商店问题

    https://www.lydsy.com/JudgeOnline/problem.php?id=4137 https://www.luogu.org/problemnew/show/P4585 火星 ...

  8. 【bzoj4137】[FJOI2015]火星商店问题

    *题目描述: 火星上的一条商业街里按照商店的编号1,2 ,…,n ,依次排列着n个商店.商店里出售的琳琅满目的商品中,每种商品都用一个非负整数val来标价.每个商店每天都有可能进一些新商品,其标价可能 ...

  9. 【洛谷】P4585 [FJOI2015]火星商店问题

    题解 题目太丧,OJ太没有良心,我永远喜欢LOJ! (TLE报成RE,垃圾洛谷,我永远喜欢LOJ) 好的,平复一下我debug了一上午崩溃的心态= =,写一写这道题的题解 把所有限制去掉,给出一个值, ...

随机推荐

  1. [Jmeter并发报错解决方案]org.apache.http.NoHttpResponseException: 10.0.4.147:8000 failed to respond

    背景:公司模型框架是Nginx+uwsgi+Django+nginx,一开始使用Jmeter进行高并发请求测试,发现成功率只有50%,换用postman,成功率100%,代码进行高并发一样不会报错. ...

  2. stm32中如何进行printf重定向用于串口调试输出

    1 在main中包含stdio.h 文件 2 Target选项框里选Use MicroLib 选项 3 在main中添加UART1_Configuration()初始化的代码 Uart1初始化,voi ...

  3. Spring Boot中使用缓存

    Spring Boot中使用缓存 随着时间的积累,应用的使用用户不断增加,数据规模也越来越大,往往数据库查询操作会成为影响用户使用体验的瓶颈,此时使用缓存往往是解决这一问题非常好的手段之一. 原始的使 ...

  4. spring data jap操作

    package com.example.demo; import com.example.entity.UserJ; import com.example.respository.UserJRespo ...

  5. tcpdump使用

    1. tcpdump选项 它的命令格式为: tcpdump [ -DenNqvX ] [ -c count ] [ -F file ] [ -i interface ] [ -r file ][ -s ...

  6. Android 模拟器下载、编译及调试

    Android 模拟器源码下载 Android 模拟器源码的下载与 Android AOSP 源码库的下载过程类似,可以参考 Google 官方提供的 Android 源码下载文档 来了解这个过程. ...

  7. 这样的SQL居然能执行

    select /*! distinct   cities.id from cities  join countries on cities.id = countries.id limit 10 */;

  8. 用python读取配置文件config.ini

    还在学习中...写的有点凌乱 感觉还是应该先学会读取配置文件才行,把一些经常需要修改的但是又经常需要用到的参数放到配置文件中方便使用(我是这么觉得的) 首先是config.ini的存放位置,我们把它放 ...

  9. Selenium(Python)页面对象+数据驱动测试框架

    整个工程的目录结构: 常用方法类: class SeleniumMethod(object): # 封装Selenium常用方法 def __init__(self, driver): self.dr ...

  10. Trie 树——搜索关键词提示

    当你在搜索引擎中输入想要搜索的一部分内容时,搜索引擎就会自动弹出下拉框,里面是各种关键词提示,这个功能是怎么实现的呢?其实底层最基本的就是 Trie 树这种数据结构. 1. 什么是 "Tri ...