做法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. struct结构体大小的计算(内存对齐)

    本次实验环境 环境1:Win10, QT 5.12 一. 背景 当普通的类型无法满足我们的需求的时候,就需要用到结构体了.结构体可衍生出结构体数组,结构体还可以嵌套结构体,这下子数据类型就丰富多彩了, ...

  2. 11.3 LVS

    LVS是什么 LVS是Linux Virtual Server的简称,也就是Linux虚拟服务器, 是一个由章文嵩博士发起的自由软件项目,它的官方站点是www.linuxvirtualserver.o ...

  3. 10.6.2 sendfile

    1.传统Linux中 I/O 的问题 2.传统的 Linux 系统的标准 I/O 接口( read. write)是基于数据拷贝的,也就是数据都是 copy_to_user 或者 copy_from_ ...

  4. Go的Select

    Go 的通道有两种操作方式,一种是带 range 子句的 for 语句,另一种则是 select 语句,它是专门为了操作通道而存在的.这里主要介绍 select 的用法. 一.select的语法 se ...

  5. 精准容量、秒级弹性,压测工具 + SAE 方案如何完美突破传统大促难关?

    作者 | 代序 阿里云云原生技术团队 本文整理自<Serverless 技术公开课>,"Serverless"公众号后台回复"入门",即可获取系列文 ...

  6. 利用水文分析方法提取山脊线和山谷线(ArcPy实现)

    一.背景 作为地形特征线的山脊线.山谷线对地形.地貌具有一定的控制作用.它们与山顶点.谷底点以及鞍部点等一起构成了地形起伏变化的骨架结构.同时由于山脊线具有分水性,山谷线具有合水性特征,使得它们在地形 ...

  7. vue3.x全局插件和组件

    做vue项目的时候,总有一些小组件或者工具类,我们需要频繁的使用,每个使用的地方再去引用相对比较麻烦,当然也有一些好处,尤其是配合组件异步加载的时候,能最更好的减少项目首次加载的体积,从而优化一些体验 ...

  8. time_formatter攻防世界学习

    time_formatter 前言:这题说实话分析量蛮大的,首先是程序内壁比较绕,而且调用了之前许多没有见到的函数---如snprintf_che,以及strsup(好像打错了),getegid(), ...

  9. 搬运1:关于对C语言中数组名取地址加减等操作的一点探究

    对于数组名取地址强制转换的操作 偶然在晚上学了C语言指针后网页闲逛找题时,被一个数组名取地址搞糊涂了,在自己试验加探索后我稍微悟了一点东西. 代码如下: #include<stdio.h> ...

  10. luogu P2746 [USACO5.3]校园网Network of Schools 题解

    前言: 火星题... 但是我调了半天,最后看了题解才明白. Wtcl 解析: 显然先缩个点. 第一问,就是问多少入度为0的点. 第二问,抽象一下就是要添加一些边,让一个DAG变成一个SCC,求最小边数 ...