Note/Solution -「洛谷 P6466」分散层叠算法
\(\mathcal{Description}\)
Link.
给定 \(m\) 个长度为 \(n\) 的有严格升序且不包含重复元素的序列 \(a_1,a_2,\cdots,a_m\),\(q\) 个询问,每次询问给出 \(x\),求 \(x\) 在每个序列中的非严格后继的异或和。强制在线。
\(m\le100\),\(n\le10^4\),\(q\le10^5\)。
\(\mathcal{Solution}\)
算是一种对多序列二分的优化科技/叭。
思考两种暴力做法:
第一种,直接在每个序列里二分求答案,则有单次 \(\mathcal O(m\log n)\)。
第二种,把 \(m\) 个序列归并为一个长度为 \(nm\) 的大序列,对于其每个位置记录其在原来 \(m\) 个序列中的非严格后继。则有 \(\mathcal O(nm\log m)-\mathcal O(m+\log(nm))\),不过空间复杂度难以接受。
而所谓“分散层叠算法”,就是对以上两种算法的平衡——假设我们求出了序列集 \(b_1,b_2,\cdots,b_m\),其中 \(b_1=a_1\),\(b_i~(i>1)\) 是对 \(a_1,a_2,\cdots,a_i\) 某种形式的“概括”,满足我们在 \(b_i\) 中二分 \(x\),能够找到 \(x\) 在实际 \(a_i\) 中的后继,同时找到 \(x\) 在 \(b_{i-1}\) 中后继的近似位置,那么就能在 \(\mathcal O(1)\) 调整该位置后迭代入 \(b_{i-1}\) 的子问题啦。
具体地,构造 \(b_i\) 为
\]
即,\(b_i\) 是 \(a_i\) 和 \(b_{i-1}\) 的偶数位置元素构成的有序序列列。归纳可证,\(b_i\) 的长度不 过 \(2n\)。同时对于 \(b_i\) 中的每个元素,记录其在 \(a_i\) 中的后继位置以及其在 \(b_{i-1}\)(完整的,包括奇数位置和偶数位置)中的后继位置(若不存在,设为最后一项,因为我们需要继续迭代调整)。
预处理时间为 \(\mathcal O(nm)\),结合上文查询方法,做到了 \(\mathcal O(nm)-\mathcal O(\log n+m)\)。这种 trick 常常与分块结合,可以加以扩展呢!
\(\mathcal{Code}\)
常数挺小的。(
/* Clearink */
#include <cstdio>
#include <algorithm>
#define rep( i, l, r ) for ( int i = l, repEnd##i = r; i <= repEnd##i; ++i )
#define per( i, r, l ) for ( int i = r, repEnd##i = l; i >= repEnd##i; --i )
inline char fgc() {
static char buf[1 << 17], *p = buf, *q = buf;
return p == q && ( q = buf + fread( p = buf, 1, 1 << 17, stdin ), p == q )
? EOF : *p++;
}
inline int rint() {
int x = 0, f = 1, s = fgc();
for ( ; s < '0' || '9' < s; s = fgc() ) f = s == '-' ? -f : f;
for ( ; '0' <= s && s <= '9'; s = fgc() ) x = x * 10 + ( s ^ '0' );
return x * f;
}
template<typename Tp>
inline void wint( Tp x ) {
if ( x < 0 ) putchar( '-' ), x = -x;
if ( 9 < x ) wint( x / 10 );
putchar( x % 10 ^ '0' );
}
const int MAXN = 1e4, MAXM = 100;
int n, m, q, D, a[MAXM + 5][MAXN + 5];
int len[MAXM + 5], top[MAXN * 2 + 5];
struct Atom { int val, nxa, nxb; };
Atom b[MAXM + 5][MAXN * 2 + 5];
inline void init() {
len[m] = n;
rep ( i, 1, n ) b[m][i] = { a[m][i], i, 0 };
static Atom tmp[MAXN + 5];
per ( i, m - 1, 1 ) {
int tlen = 0;
Atom* curb = b[i];
for ( int j = 2; j <= len[i + 1]; j += 2 ) {
tmp[++tlen] = { b[i + 1][j].val, 0, j };
}
int p = 1, q = 1;
rep ( j, 1, n ) {
for ( ; p <= tlen && tmp[p].val <= a[i][j]; ++p ) {
*++curb = tmp[p], curb->nxa = j;
}
for ( ; q < len[i + 1] && b[i + 1][q].val <= a[i][j]; ++q );
*++curb = { a[i][j], j, q };
}
for ( ; p <= tlen; *++curb = tmp[p++] );
len[i] = curb - b[i];
#ifdef RYBY
printf( "b[%d]:\n", i );
rep ( j, 1, len[i] ) {
printf( "(%d,%d,%d) ", b[i][j].val, b[i][j].nxa, b[i][j].nxb );
}
putchar( '\n' );
#endif
}
rep ( i, 1, len[1] ) top[i] = b[1][i].val;
}
int main() {
n = rint(), m = rint(), q = rint(), D = rint();
rep ( i, 1, m ) rep ( j, 1, n ) a[i][j] = rint();
init();
for ( int qid = 1, x, ans = 0; qid <= q; ++qid ) {
x = rint() ^ ans, ans = 0;
int p = std::lower_bound( top + 1, top + len[1] + 1, x ) - top;
ans ^= a[1][b[1][p].nxa];
#ifdef RYBY
printf( "in %d, p=%d: %d\n", 1, p, a[1][b[1][p].nxa] );
#endif
rep ( i, 2, m ) {
p = b[i - 1][p].nxb;
for ( ; p < len[i] && b[i][p + 1].val <= x; ++p );
for ( ; p > 1 && b[i][p - 1].val >= x; --p );
#ifdef RYBY
printf( "in %d, p=%d: %d\n", i, p, a[i][b[i][p].nxa] );
#endif
if ( a[i][b[i][p].nxa] >= x ) ans ^= a[i][b[i][p].nxa];
}
if ( !( qid % D ) ) wint( ans ), putchar( '\n' );
}
return 0;
}
Note/Solution -「洛谷 P6466」分散层叠算法的更多相关文章
- Note/Solution -「洛谷 P5158」「模板」多项式快速插值
\(\mathcal{Description}\) Link. 给定 \(n\) 个点 \((x_i,y_i)\),求一个不超过 \(n-1\) 次的多项式 \(f(x)\),使得 \(f(x ...
- Solution -「洛谷 P4372」Out of Sorts P
\(\mathcal{Description}\) OurOJ & 洛谷 P4372(几乎一致) 设计一个排序算法,设现在对 \(\{a_n\}\) 中 \([l,r]\) 内的元素排 ...
- Solution -「洛谷 P4198」楼房重建
\(\mathcal{Description}\) Link. 给定点集 \(\{P_n\}\),\(P_i=(i,h_i)\),\(m\) 次修改,每次修改某个 \(h_i\),在每次修改后 ...
- Solution -「洛谷 P6577」「模板」二分图最大权完美匹配
\(\mathcal{Description}\) Link. 给定二分图 \(G=(V=X\cup Y,E)\),\(|X|=|Y|=n\),边 \((u,v)\in E\) 有权 \(w( ...
- Solution -「洛谷 P6021」洪水
\(\mathcal{Description}\) Link. 给定一棵 \(n\) 个点的带点权树,删除 \(u\) 点的代价是该点点权 \(a_u\).\(m\) 次操作: 修改单点点权. ...
- Solution -「洛谷 P4719」「模板」"动态 DP" & 动态树分治
\(\mathcal{Description}\) Link. 给定一棵 \(n\) 个结点的带权树,\(m\) 次单点点权修改,求出每次修改后的带权最大独立集. \(n,m\le10^5 ...
- Solution -「洛谷 P5236」「模板」静态仙人掌
\(\mathcal{Description}\) Link. 给定一个 \(n\) 个点 \(m\) 条边的仙人掌,\(q\) 组询问两点最短路. \(n,q\le10^4\),\(m\ ...
- Solution -「洛谷 P4320」道路相遇
\(\mathcal{Description}\) Link. 给定一个 \(n\) 个点 \(m\) 条边的连通无向图,并给出 \(q\) 个点对 \((u,v)\),询问 \(u\) 到 ...
- Solution -「洛谷 P5827」边双连通图计数
\(\mathcal{Description}\) link. 求包含 \(n\) 个点的边双连通图的个数. \(n\le10^5\). \(\mathcal{Solution}\) ...
随机推荐
- react中使用charles实现本地数据mock
首先下载charles软件地址,更详细的使用方法都包含在操作文档里,包含汉化版补丁(下载后查看) 链接:https://pan.baidu.com/s/1Q5rMbcX0Wus7AwdGUWa-Wg ...
- Go语言实战-爬取校花网图片
一.目标网站分析 爬取校花网http://www.xiaohuar.com/大学校花所有图片. 经过分析,所有图片分为四个页面,http://www.xiaohuar.com/list-1-0.htm ...
- test_1 计算字符串最后一个单词的长度,单词以空格隔开
题目描述:计算字符串最后一个单词的长度,单词以空格隔开. 输入描述: 一行字符串,非空,长度小于5000. 输出描述: 整数N,最后一个单词的长度. #coding=utf-8 str = raw_ ...
- Android官方文档翻译 十 2.3Styling the Action Bar
Styling the Action Bar 设计菜单栏的样式 This lesson teaches you to 这节课教给你 Use an Android Theme 使用一个Android主题 ...
- 微信小程序云开发指南
一.初识云开发 官方文档 小程序·云开发是微信团队联合腾讯云推出的专业的小程序开发服务. 开发者可以使用云开发快速开发小程序.小游戏.公众号网页等,并且原生打通微信开放能力. 开发者无需搭建服务器,可 ...
- vue学习5-js表达式
三目运算符 <!DOCTYPE html> <html lang='en'> <head> <meta charset='UTF-8'> <m ...
- IoC容器-Bean管理XML方式(注入空值和特殊符号)
Ioc操作Bean管理(xml注入其他类型属性), 字面量 (1)null值 (2)属性值包含特殊符号
- 使用 MVVM Toolkit Source Generators
关于 MVVM Toolkit 最近 .NET Community Toolkit 发布了 8.0.0 preview1,它包含了从 Windows Community Toolkit 迁移过来的以下 ...
- 边带权并查集 学习笔记 & 洛谷P1196 [NOI2002] 银河英雄传说 题解
花了2h总算把边带权并查集整明白了qaq 1.边带权并查集的用途 众所周知,并查集擅长维护与可传递关系有关的信息.然而我们有时会发现并查集所维护的信息不够用,这时"边带权并查集"就 ...
- Filter+Redis解决项目之间调用的幂等性
幂等(idempotent.idempotence)是一个数学与计算机学概念,常见于抽象代数中. 在编程中一个幂等操作的特点是其任意多次执行所产生的影响均与一次执行的影响相同 在项目远程调用中,如果接 ...