做法1

对于每一个询问,直接暴力在每一个序列中二分查询

时间复杂度为$o(nk)-o(k\log n)$

做法2

将所有序列合并后排序,并对每一个元素预处理出每个序列中第一个大于等于其的元素(位置),那么只需要在总序列中二分并输出该位置预处理的答案即可

关于这个预处理,显然只需要从后往前扫描一遍总序列即可

时间复杂度为$o(nk^{2})-o(k+\log nk)$

做法3

使用分治归并,并对合并后序列的每一个元素预处理出参与合并的两个序列第一个大于等于其的元素位置

对于查询,只需要在总序列中二分一次,并根据预处理的信息递归下去即可

时间复杂度为$o(nk\log k)-o(k+\log nk)$

做法4

事实上,只需要将下标为偶数的项参与合并,此时即找到第一个大于等于"其"的偶数项,再判断上一项是否大于等于"其"即可,这样查询的复杂度并没有变化

(另外,为了避免特判可以强制将最后一项也加入)

沿用做法3,并做此优化,归纳可得每一个位置上的序列长度都为$n$,复杂度即降为$o(nk)$

当然,直接沿用做法2也是可以的,即令$\{b_{k}\}=\{a_{k}\}$且$\{b_{i}\}$为$\{a_{i}\}$和$\{b_{i+1}\}$合并的结果,同样在合并后预处理相同的信息,通过此优化不难证明$\{b_{i}\}$的长度和为$o(nk)$

时间复杂度为$o(nk)-o(k+\log nk)$

 1 #include<bits/stdc++.h>
2 using namespace std;
3 #define N 10005
4 #define K 105
5 #define D 2
6 int n,k,m,d,x,ans,num[11],a[K][N],Pos[2],b[K][N<<1],pos[K][N<<1][2];
7 int read(){
8 int x=0;
9 char c=getchar();
10 while ((c<'0')||(c>'9'))c=getchar();
11 while ((c>='0')&&(c<='9')){
12 x=x*10+(c-'0');
13 c=getchar();
14 }
15 return x;
16 }
17 void write(int x,char c='\0'){
18 while (x){
19 num[++num[0]]=x%10;
20 x/=10;
21 }
22 if (!num[0])putchar('0');
23 while (num[0])putchar(num[num[0]--]+'0');
24 putchar(c);
25 }
26 int main(){
27 n=read(),k=read(),m=read(),d=read();
28 for(int i=1;i<=k;i++)
29 for(int j=1;j<=n;j++)a[i][j]=read();
30 for(int i=k;i;i--){
31 int x=1,y=D;
32 while ((x<=n)||(y<=b[i+1][0])){
33 if ((x<=n)&&((y>b[i+1][0])||(a[i][x]<b[i+1][y]))){
34 b[i][++b[i][0]]=a[i][x];
35 pos[i][b[i][0]][0]=x++;
36 }
37 else{
38 b[i][++b[i][0]]=b[i+1][y];
39 pos[i][b[i][0]][1]=y;
40 if (y==b[i+1][0])y+=D;
41 else y=min(y+D,b[i+1][0]);
42 }
43 }
44 memset(Pos,0,sizeof(Pos));
45 for(int j=b[i][0];j;j--)
46 for(int p=0;p<2;p++){
47 if (pos[i][j][p])Pos[p]=pos[i][j][p];
48 pos[i][j][p]=Pos[p];
49 }
50 }
51 for(int i=1;i<=m;i++){
52 x=read(),x^=ans;
53 ans=0;
54 int y=lower_bound(b[1]+1,b[1]+b[1][0]+1,x)-b[1];
55 for(int j=1;j<=k;j++){
56 if (pos[j][y][0])ans^=a[j][pos[j][y][0]];
57 if (!pos[j][y][1])break;
58 y=pos[j][y][1];
59 while ((y>1)&&(b[j+1][y-1]>=x))y--;
60 }
61 if (i%d==0)write(ans,'\n');
62 }
63 return 0;
64 }

拓展

给定一张$k$个点的DAG,每个点上有一个长为$n$的单调不下降序列$\{a_{i}\}$

$m$次询问$x$和一条路径,求出每一个路径上的序列中第一个大于等于$z$的元素

保证每一个点的入度和出度均不超过$d$

题解:

类似于做法4,在叶子上令$\{b_{leaf}\}=\{a_{leaft}\}$且$\{b_{i}\}$为$\{a_{i}\}$和$\forall (i,j)\in E,\{b_{j}\}$合并的结果(后者合并时只取下标为$d+1$的倍数的项),并预处理相同的信息

令$L_{i}$​为$i$​上序列的长度,则有$L_{i}=n+\frac{\sum_{(i,j)\in E}L_{j}}{d+1}$​,进而有
$$
\sum_{i\in V}L_{i}=\sum_{i\in V}(n+\frac{\sum_{(i,j)\in E}L_{j}}{d+1})\le \sum_{i\in V}(n+\frac{d}{d+1}L_{i})
$$
将其化简,也即$\sum_{i\in V}L_{i}\le (d+1)nk$

简单分析,可以发现预处理的时空复杂度均为$o(d\sum_{i\in V}L_{i})$,由此也即$o(d^{2}nk)$

另外,由于只取了$d+1$的倍数项,查询时最多要向前找$d$次,即最坏要找$o(dk)$次

(显然$d$要很小此做法才较优,因此二分做到$o(k\log d)$没有意义)

时间复杂度为$o(d^{2}nk)-o(dk+\log nk)$

[luogu6466]分散层叠算法的更多相关文章

  1. Note/Solution -「洛谷 P6466」分散层叠算法

    \(\mathcal{Description}\)   Link.   给定 \(m\) 个长度为 \(n\) 的有严格升序且不包含重复元素的序列 \(a_1,a_2,\cdots,a_m\),\(q ...

  2. [Comet1173]最简单的题

    称区间$[l,r]$的"信息"为其的答案和第一个.最后一个大于$x$的位置,显然通过$[l,mid]$和$[mid+1,r]$的信息可以$o(1)$合并得到$[l,r]$的信息 考 ...

  3. [loj6278]数列分块入门2

    做法1 以$K$为块大小分块,并对每一个块再维护一个排序后的结果,预处理复杂度为$o(n\log K )$ 区间修改时将整块打上标记,散块暴力修改并归并排序,单次复杂度为$o(\frac{n}{K}+ ...

  4. [cf1178G]The Awesomest Vertex

    2020年论文题,这里给出了一个$o(n\log^{2}n+m\log^{3}n)$的做法,例题3即为原题 1.例题1 题面 给定$n$个一次函数$f_{i}(x)$,$m$次查询$F(x)=\max ...

  5. 借助 SIMD 数据布局模板和数据预处理提高 SIMD 在动画中的使用效率

    原文链接 简介 为发挥 SIMD1 的最大作用,除了对其进行矢量化处理2外,我们还需作出其他努力.可以尝试为循环添加 #pragma omp simd3,查看编译器是否成功进行矢量化,如果性能有所提升 ...

  6. 前端入门4-CSS属性样式表

    本篇文章已授权微信公众号 dasu_Android(大苏)独家发布 声明 本系列文章内容全部梳理自以下四个来源: <HTML5权威指南> <JavaScript权威指南> MD ...

  7. 前端入门3-CSS基础

    本篇文章已授权微信公众号 dasu_Android(大苏)独家发布 声明 本系列文章内容全部梳理自以下四个来源: <HTML5权威指南> <JavaScript权威指南> MD ...

  8. CSS概念【记录】

    1.CSS语法 2.@规则 3.注释 4.层叠 5.优先级 6.继承 7.值 8.块格式化上下文 9.盒模型 10.层叠上下文 11.可替换元素 12.外边距合并 13.包含块 14.视觉格式化模型 ...

  9. CSS学习摘要-语法和选择器

    主要摘自网络开发者. 从最基本的层次来看,CSS是由两块内容组合而成的: 属性(Property):一些人类可理解的标识符,这些标识符指出你想修改哪一些样式,例如:字体,宽度,背景颜色等. 属性值(V ...

随机推荐

  1. Java编程开发学习路线图(附所有免费课程+在线自测)

    转自  https://yq.aliyun.com/articles/134286?spm=5176.100239.0.0.1UfveS 摘要: 长期以来,Java一直占据TIOBE编程语言排行版第一 ...

  2. Scrum Meeting 0427

    零.说明 日期:2021-4-27 任务:简要汇报两日内已完成任务,计划后两日完成任务 一.进度情况 组员 负责 两日内已完成的任务 后两日计划完成的任务 qsy PM&前端 完成部分登录,注 ...

  3. Scrum Meeting 0529

    零.说明 日期:2021-5-29 任务:简要汇报七日内已完成任务,计划后两日完成任务 一.进度情况 组员 负责 七日内已完成的任务 后两日计划完成的任务 困难 qsy PM&前端 完成后端管 ...

  4. flink中使用lambda表达式

    flink中使用lambda表达式 1.使用lambda的一个示例 2.使用上面这种写法通常或得到如下错误 3.解决方案 4.建议 5.完整代码 在 java8中有一种新的语法糖,即 lambda表达 ...

  5. 21.6.23 test

    省选 模拟赛 今天考的是一套题目背景和描述会被[数据删除]的模拟赛. 犯了几个傻逼错. \(T1\) 把两种情况的概率看反了,写的暴力.\(35->5\) pts. \(T2\) 以为想到了正解 ...

  6. MyBatis源码分析(七):动态代理(Mybatis核心机制)

    一.动态代理 动态代理是一种比较高级的代理模式,它的典型应用就是Spring AOP. 在传统的动态代理模式中,客户端通过ProxySubject调用RealSubject类的request( )方法 ...

  7. Go语言核心36讲(Go语言进阶技术十一)--学习笔记

    17 | go语句及其执行规则(下) 知识扩展 问题 1:怎样才能让主 goroutine 等待其他 goroutine? 我刚才说过,一旦主 goroutine 中的代码执行完毕,当前的 Go 程序 ...

  8. 深入理解 Linux的进程,线程,PID,LWP,TID,TGID

    转载:https://www.linuxidc.com/Linux/2019-03/157819.htm 在Linux的top和ps命令中,默认看到最多的是pid (process ID),也许你也能 ...

  9. 转:进行vivado开发时,Generate Bitstream报错[DRC NSTD-1],详细解决步骤

    报错如下 [Drc 23-20] Rule violation (NSTD-1) Unspecified I/O Standard - 4 out of 142 logical ports use I ...

  10. Linux&C ——信号以及信号处理

    linux信号的简单介绍 信号的捕捉和处理 信号处理函数的返回 信号的发送 信号的屏蔽 一:linux信号的简单介绍. 信号提供给我们一种异步处理事件的方法,由于进程之间彼此的地址空间是独立的,所以进 ...