题面

凇睦是一个喜欢探险的女孩子,这天她到一片海域上来探险了。

在这片海域上一共有 n 座岛屿排成一排,标号为 1, 2, 3, . . . , n。每座岛屿有两个权值,分别为劳累度 ai 和有趣度 bi

对于一座劳累度为 a,有趣度为 b 的小岛,如果这个小岛满足 (a ⊕ c) ≤ min(b, d),凇睦到这座岛探险就会感到开心,其中 c 表示凇睦到岛上去之前就有的劳累度(称作初始劳累度),同理 d 代表凇睦的初始有趣度。⊕ 表示二进制异或(即二进制表示下不进位的加法)。

为了玩的更尽兴,凇睦会向你询问 q 次,每次给出一个区间 [li, ri] 和两个数 ci, di,你需要告诉凇睦若她的初始劳累度为 ci,初始有趣度为 di,则有多少个标号在 [li, ri] 这个区间内的岛屿能使凇睦探险时感到开心。

【输入格式】

从文件 island.in 中读入数据。
第一行两个正整数 n, q 分别表示岛屿的数量和询问的数量。
接下来 n 行,每行两个整数 ai, bi 分别表示第 i 座岛屿的劳累度和有趣度。
接下来 q 行,每行四个正整数 li, ri, ci, di 分别表示区间左端点,区间右端点,初始劳累度与初始有趣度。

【输出格式】

输出到文件 island.out 中。
输出一共 q 行,每行一个整数对应一个询问的答案。

题解

我们发现询问可以离线,那就先离线下来。

我们发现 [li, ri] 可以拆成 ri 的贡献减去 li-1 的贡献,那就把它拆开。

然后就可以把所有原序列上的点和所有询问的两个点先按照 bi 或 di 从小到大排序,放在 CDQ 分治中,在分治中按照位置下标排序,这样就消除了 bi 和 di ,以及 [li, ri] 的限制了。接下来才是重头戏,维护 (a ⊕ c) ≤ min(b, d) 这个条件。

我们建两棵 Trie 树,一棵维护 (a ⊕ c) ≤ b ,另一棵维护 (a ⊕ c) ≤ d。


对于第一棵树,其实并没有普通的 Trie 树插入操作那么简单。已知的是 a 和 b,我们可以令 Trie 树上的点表示加进去的 a 对该点范围内的 c 的贡献,这样,我们遍历到 a 的某一位时,假设到了 Trie 树上的结点 p,作如下讨论:

  • a 的这一位是 1
    如果 a 这一位变成 0 ,后面的位置全为 1,a 的值仍然 ≤ b,说明 p 的 “1” 子树内的 c 肯定都符合条件了(不管 c 后面的是什么,只要这一位是 1,a ⊕ c 就能 ≤ b),那么我们就把 p 的 “1” 儿子的权值 ++,表示这个点里所有 c 的答案都+1。然后把 p 赋值为 “0” 儿子继续跑下一位,因为 “0” 儿子不一定全是合法的 c 。
    如果 a 这一位变成 0 ,后面的位置全为 1,a 的值 > b,说明 p 的 “0” 子树内的 c 肯定都符合条件(不管 c 后面的是什么,只要这一位是 0,a ⊕ c 就不可能 ≤ b),那么我们就把 p 赋值为 “1” 儿子继续跑下一位,因为 “1” 儿子有可能有合法 c。此时别忘了把 a 的这一位变为 0,表示异或了 1.
  • a 的这一位是 0,类似的:
    如果 a 这一位保持 0 ,后面的位置全为 1,a 的值 ≤ b,说明 p 的 “0” 子树内的 c 肯定都符合条件了(不管 c 后面的是什么,只要这一位是 0,a ⊕ c 就能 ≤ b),那么我们就把 p 的 “0” 儿子的权值 ++ 。然后把 p 赋值为 “1” 儿子继续跑下一位,因为 “1” 儿子里不一定全是合法的 c 。此时别忘了把 a 的这一位变为 1,表示异或了 1.
    如果 a 这一位保持 0 ,后面的位置全为 1,a 的值 > b,说明 p 的 “1” 子树内的 c 肯定都不符合条件(不管 c 后面的是什么,只要这一位是 1,a ⊕ c 就不可能 ≤ b),那么我们就把 p 赋值为 “0” 儿子继续跑下一位,因为 “0” 儿子有可能有合法 c。
  • 最后到了一个末结点 p,如果此时的 a ≤ b,那我们还得把 p 的权值 ++,因为之前没统计到。

询问 c 的时候就直接像跑普通 Trie 一样跑一遍,然后统计路径上的权值和就完了。


对于第二棵 Trie 树,由于每个点的 b 没有用了,我们只知道 a ,那么不妨就像普通 Trie 树一样插入 a ,然后统计子树元素个数和。

询问的时候,d 就有用了,此时已知 c, d ,我们在 Trie 树上找合法的 a ,一样是大讨论,别忘了最后到末结点要判断加不加权值。参考第一棵 Tire 树的插入操作。


讲完了!CDQ 分治里我们对于 b ≤ d 和 b > d 的两种情况分别在 Trie1 和 Trie2 上计算就行了。时间复杂度 O(n log2n) 。

CODE

场上差点肝出来的 CDQ 代码(Trie 是调对了的):

  1. #include<set>
  2. #include<map>
  3. #include<queue>
  4. #include<vector>
  5. #include<cstdio>
  6. #include<cstring>
  7. #include<iostream>
  8. #include<algorithm>
  9. using namespace std;
  10. #define MAXN 200005
  11. #define MAXC 26
  12. #define DB double
  13. #define LL long long
  14. #define ENDL putchar('\n')
  15. #define lowbit(x) (-(x) & (x))
  16. LL read() {
  17. LL f = 1,x = 0;char s = getchar();
  18. while(s < '0' || s > '9') {if(s=='-')f = -f;s = getchar();}
  19. while(s >= '0' && s <= '9') {x=x*10+(s-'0');s = getchar();}
  20. return f * x;
  21. }
  22. int n,m,i,j,s,o,k;
  23. struct tr{
  24. int s[2];
  25. int nm;
  26. tr(){s[0]=s[1]=nm=0;}
  27. };
  28. int CNT1,CNT2;
  29. tr tri1[MAXN*48],tri2[MAXN*32];
  30. int newn1() {tri1[++ CNT1] = tr();return CNT1;}
  31. int newn2() {tri2[++ CNT2] = tr();return CNT2;}
  32. int addtr1(int x,int a,int b) {
  33. if(!x) x = newn1();
  34. int p = x;
  35. for(int i = 23;i >= 0;i --) {
  36. if(!tri1[p].s[0]) tri1[p].s[0] = newn1();
  37. if(!tri1[p].s[1]) tri1[p].s[1] = newn1();
  38. int pr = a - (a & ((1<<(i+1))-1));
  39. int d = (a & (1<<i)) ? 1:0;
  40. if(pr+(1<<i)-1 <= b) {tri1[tri1[p].s[d]].nm ++;p = tri1[p].s[d^1];a ^= ((d^1)*(1<<i));}
  41. else p = tri1[p].s[d],a ^= (d*(1<<i));
  42. }
  43. if(a <= b) tri1[p].nm ++;
  44. return x;
  45. }
  46. int addtr2(int x,int a) {
  47. if(!x) x = newn2();
  48. int p = x;
  49. for(int i = 23;i >= 0;i --) {
  50. int d = (a & (1<<i)) ? 1:0;
  51. if(!tri2[p].s[d]) tri2[p].s[d] = newn2();
  52. p = tri2[p].s[d]; tri2[p].nm ++;
  53. }
  54. return x;
  55. }
  56. int findtr1(int x,int a) {
  57. if(!x) return 0;
  58. int p = x,as = 0;
  59. for(int i = 23;i >= 0;i --) {
  60. int d = ((a & (1<<i)) ? 1:0);
  61. if(!tri1[p].s[d]) return as;
  62. p = tri1[p].s[d]; as += tri1[p].nm;
  63. }return as;
  64. }
  65. int findtr2(int x,int a,int b) {
  66. if(!x) return 0;
  67. int p = x,as = 0;
  68. for(int i = 23;i >= 0;i --) {
  69. if(!p) return as;
  70. int pr = a - (a & ((1<<(i+1))-1));
  71. int d = (a & (1<<i)) ? 1:0;
  72. if(pr+(1<<i)-1 <= b) {as += tri2[tri2[p].s[d]].nm;p = tri2[p].s[d^1];a ^= ((d^1)*(1<<i));}
  73. else p = tri2[p].s[d],a ^= (d*(1<<i));
  74. }
  75. if(a <= b) as += tri2[p].nm;
  76. return as;
  77. }
  78. int ai[MAXN],bi[MAXN];
  79. int ci[MAXN],di[MAXN];
  80. int as[MAXN];
  81. struct it{
  82. int a,b,id,op,pos,ad;it(){a=b=id=op=pos=ad=0;}
  83. it(int D,int O,int P,int A,int B,int I) {ad=D;op=O;pos=P;a=A;b=B;id=I;}
  84. }p[MAXN<<1];
  85. int cntp;
  86. bool cmpb(it x,it y) {return x.b < y.b;}
  87. bool cmpp(it a,it b) {return (a.pos == b.pos ? (a.op > b.op):(a.pos < b.pos));}
  88. void solve(int l,int r) {
  89. if(l >= r) return ;
  90. int mid = (l + r) >> 1;
  91. solve(l,mid);solve(mid+1,r);
  92. sort(p + l,p + r + 1,cmpp);
  93. CNT1 = CNT2 = 0;
  94. int rt1 = 0,rt2 = 0;
  95. for(int i = l;i <= r;i ++) {
  96. if(p[i].op == 1) {
  97. if(p[i].ad <= mid) rt1 = addtr1(rt1,p[i].a,p[i].b);
  98. else rt2 = addtr2(rt2,p[i].a);
  99. }
  100. else {
  101. int y = p[i].id,opt=1;
  102. if(y < 0) y=-y,opt=-opt;
  103. if(p[i].ad <= mid) as[y] += opt*findtr2(rt2,p[i].a,p[i].b);
  104. else as[y] += opt*findtr1(rt1,p[i].a);
  105. }
  106. }
  107. return ;
  108. }
  109. int main() {
  110. freopen("island.in","r",stdin);
  111. freopen("island.out","w",stdout);
  112. n = read();m = read();
  113. for(int i = 1;i <= n;i ++) {
  114. ai[i] = read();bi[i] = read();
  115. p[++ cntp] = it(0,1,i,ai[i],bi[i],i);
  116. }
  117. for(int i = 1;i <= m;i ++) {
  118. s = read();o = read();
  119. ci[i] = read();di[i] = read();
  120. p[++ cntp] = it(0,0,s-1,ci[i],di[i],-i);
  121. p[++ cntp] = it(0,0,o,ci[i],di[i],i);
  122. }
  123. sort(p + 1,p + 1 + cntp,cmpb);
  124. for(int i = 1;i <= cntp;i ++) p[i].ad = i;
  125. solve(1,cntp);
  126. for(int i = 1;i <= m;i ++) {
  127. printf("%d\n",as[i]);
  128. }
  129. return 0;
  130. }
  131. /*
  132. 20 10
  133. 215 144
  134. 2 110
  135. 174 132
  136. 214 142
  137. 116 108
  138. 155 192
  139. 236 208
  140. 216 214
  141. 99 220
  142. 236 118
  143. 190 81
  144. 230 131
  145. 10 238
  146. 189 198
  147. 183 13
  148. 45 193
  149. 14 234
  150. 208 192
  151. 126 19
  152. 49 38
  153. 7 14 251 184
  154. 2 18 89 76
  155. 11 15 49 196
  156. 8 11 83 139
  157. 10 15 119 239
  158. 9 16 148 120
  159. 11 17 225 34
  160. 15 16 3 46
  161. 14 15 86 227
  162. 7 18 252 103
  163. */

CCF NOI Online 2021 提高组 T3 岛屿探险(CDQ 分治,Trie 树)的更多相关文章

  1. CCF NOI Online 2021 提高组 赛后心得

    T1 做个,不会,拿到 20 pts 跑路. 注意后面有个 K = 1 的部分分,这个可以递推求 b 的个数,然后直接乘上 a0 . 官方正解讲得极其详细,我还是第一次见到可以 O(K2) 做 1~n ...

  2. CCF NOI Online 2021 提高组 T2 积木小赛 (子序列自动机+后缀自动机,O(n^2))

    题面 Alice 和 Bob 最近热衷于玩一个游戏--积木小赛. Alice 和 Bob 初始时各有 n 块积木从左至右排成一排,每块积木都被标上了一个英文小写字母. Alice 可以从自己的积木中丢 ...

  3. [NOI Online 2021 提高组] 积木小赛

    思路不说了. 想起来自己打比赛的时候,没睡好.随便写了个\(HASH\),模数开小一半分都没有. 然后学了\(SAM\),发现这个判重不就是个水题. \(SAM\)是字串tire的集合体. 随便\(d ...

  4. [题解] [NOI Online 2021 入门组 T3] 重力球

    题目大意 在一个 \(n\times n\) 的矩形中,题目会给出 \(m\) 个障碍物.有两个小球,你可以选定四个方向(上下左右)的其中一个,小球会朝着这四个方向一直滚动,直到遇到障碍物或是矩形的边 ...

  5. luogu P6570 [NOI Online #3 提高组]优秀子序列 二进制 dp

    LINK:P6570 [NOI Online #3 提高组]优秀子序列 Online 2的T3 容易很多 不过出于某种原因(时间不太够 浪了 导致我连暴力的正解都没写. 容易想到 f[i][j]表示前 ...

  6. JZOJ2020年8月11日提高组T3 页

    JZOJ2020年8月11日提高组T3 页 题目 Description 战神阿瑞斯听说2008年在中华大地上,将举行一届规模盛大的奥林匹克运动会,心中顿觉异常兴奋,他想让天马在广阔的天空上,举行一场 ...

  7. 【GDKOI2014】JZOJ2020年8月13日提高组T3 壕壕的寒假作业

    [GDKOI2014]JZOJ2020年8月13日提高组T3 壕壕的寒假作业 题目 Description Input Output 输出n行.第i行输出两个整数,分别表示第i份作业最早完成的时刻以及 ...

  8. JZOJ2020年8月10日提高组T3 玩诈欺的小杉

    JZOJ2020年8月10日提高组T3 玩诈欺的小杉 题目 Description 是这样的,在小杉的面前有一个N行M列的棋盘,棋盘上有\(N*M\)个有黑白棋的棋子(一面为黑,一面为白),一开始都是 ...

  9. 【佛山市选2013】JZOJ2020年8月7日提高组T3 海明距离

    [佛山市选2013]JZOJ2020年8月7日提高组T3 海明距离 题目 描述 对于二进制串a,b,他们之间的海明距离是指两个串异或之后串中1的个数.异或的规则为: 0 XOR 0 = 0 1 XOR ...

随机推荐

  1. 2.Tensor Shape《Pytorch神经网络高效入门教程》Deeplizard

            ,之后,我们张量和基础数据的形状酱油卷积运算来改变. 卷积改变了高度和宽度维度以及颜色通道的数量.

  2. c++ 树状数组

    关于树状数组 树状数组,即 Binary Indexed Tree ,主要用于维护查询前缀和 属于 log 型数据结构 和线段树比较 都是 log 级别 树状数组常数.耗费的空间.代码量都比线段树小 ...

  3. ExtJS 布局-Anchor 布局(Anchor layout)

    更新记录: 2022年5月30日 发布本篇 1.说明 anchor布局类似auto布局从上到下进行堆叠,但不同的是其可以指定每个元素相对于容器大小的比例. 当调整父容器大小,容器根据指定的规则调整所有 ...

  4. Java集合框架(一)-ArrayList

    大佬理解->Java集合之ArrayList 1.ArrayList的特点 存放的元素有序 元素不唯一(可以重复) 随机访问快 插入删除元素慢 非线程安全 2.底层实现 底层初始化,使用一个Ob ...

  5. NLog自定义Target之MQTT

    NLog是.Net中最流行的日志记录开源项目(之一),它灵活.免费.开源 官方支持文件.网络(Tcp.Udp).数据库.控制台等输出 社区支持Elastic.Seq等日志平台输出 实时日志需求 在工业 ...

  6. 你是否有一个梦想?用JavaScript[vue.js、react.js......]开发一款自定义配置视频播放器

    前言沉寂了一周了,打算把这几天的结果呈现给大家.这几天抽空就一直在搞一个自定义视频播放器,为什么会有如此想法?是因为之前看一些学习视频网站时,看到它们做的视频播放器非常Nice!于是,就打算抽空开发一 ...

  7. 《阿里云天池大赛赛题解析》——O2O优惠卷预测

    赛事链接:https://tianchi.aliyun.com/competition/entrance/231593/introduction?spm=5176.12281925.0.0.7e157 ...

  8. Java多线程下载分析

    为什么要多线程下载 俗话说要以终为始,那么我们首先要明确多线程下载的目标是什么,不外乎是为了更快的下载文件.那么问题来了,多线程下载文件相比于单线程是不是更快? 对于这个问题可以看下图. 横坐标是线程 ...

  9. Java中Double类型数据比较大小

    方法一:转成字符串之后比较 如果要比较的两个double数据的字符串精度相等,可以将数据转换成string然后借助string的equals方法来间接实现比较两个double数据是否相等.注意这种方法 ...

  10. P3480 [POI2009]KAM-Pebbles 题解

    题目链接 首先,这道题看上去就是个博弈论,很显然的 \(Nim\) 游戏. 因为每一个的取法都和它的上一位有关. 有一种非常显然的转换方式 :我们把这若干堆石子从前向后做一个差分 . 我们记 \(a_ ...