\(\mathcal{Description}\)

  Link.

  给定序列 \(\{(a,b)_n\}\),\(q\) 组形如 \((l,r,c,d)\) 的询问,求

\[\Big|\{i\in[l,r]~\big|~a_i\oplus c\le \min\{b_i,d\}\}\Big|
\]

  \(n,q\le10^5\),\(a,b,c,d<2^{24}\)。

\(\mathcal{Solution}\)

  CDQ 不熟练欸……

  在 \(i\) 的限制条件中,最离谱的应该是 \(\le\min\{b_i,d\}\),再联系部分分,可以想到分别计算两种情况。把原序列当做单点修改,询问离线为前缀查询,发现这就是一个偏序对的贡献问题,外层套一个 CDQ 分治处理。

  接下来,我们需要应对动态插入和询问,分 \((a,b)\) 一定用 \(c\) 查询和 \(a\) 一定用 \((c,d)\) 查询两种情况写两棵不需要持久化的 Trie 树分别维护即可。

  复杂度 \(\mathcal O((n+q)\log(n+q)\log\max\{a,b,c,d\})\)。

\(\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 int rint() {
int x = 0, f = 1, s = getchar();
for ( ; s < '0' || '9' < s; s = getchar() ) f = s == '-' ? -f : f;
for ( ; '0' <= s && s <= '9'; s = getchar() ) 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 = 1e5, MAXWID = 23;
int n, q, a[MAXN + 5], b[MAXN + 5], qall, ans[MAXN * 2 + 5];
int otmp[MAXN * 3 + 5], ord[MAXN * 3 + 5]; struct Event {
int r, c, d, id;
Event(): r( 0 ), c( 0 ), d( 0 ), id( 0 ) {}
Event( const int r_, const int c_, const int d_, const int id_ ):
r( r_ ), c( c_ ), d( d_ ), id( id_ ) {}
inline bool operator < ( const Event& t ) const {
return r != t.r ? r < t.r : id < t.id;
}
} evt[MAXN * 3 + 5]; struct DTrie { // maintain a[i] xor c <= d.
static const int MAXND = 2.3e6;
int node, root, siz[MAXND + 5], ch[MAXND + 5][2];
DTrie() { clear(); }
inline void clear() { node = root = 1, siz[1] = ch[1][0] = ch[1][1] = 0; }
inline int crtnd() {
int u = ++node;
siz[u] = ch[u][0] = ch[u][1] = 0;
return u;
} inline void insert( int& u, const int x, const int d ) {
if ( !u ) u = crtnd();
++siz[u];
if ( ~d ) insert( ch[u][( x >> d ) & 1], x, d - 1 );
} inline int query( const int u, const int c, const int lim, const int d ) {
if ( !u ) return 0;
if ( !~d ) return siz[u];
int p = c >> d & 1, q = lim >> d & 1, ret = 0;
if ( q ) return siz[ch[u][p]] + query( ch[u][!p], c, lim, d - 1 );
else return query( ch[u][p], c, lim, d - 1 );
}
} dtr; struct BTrie { // maintain a[i] xor c <= b[i].
static const int MAXND = 2.3e6;
int node, root, tag[MAXND + 5], ch[MAXND + 5][2];
BTrie() { clear(); }
inline void clear() { node = root = 1, tag[1] = ch[1][0] = ch[1][1] = 0; }
inline int crtnd() {
int u = ++node;
tag[u] = ch[u][0] = ch[u][1] = 0;
return u;
} inline void insert( int& u, const int a, const int b, const int d ) {
if ( !u ) u = crtnd();
if ( !~d ) return void( ++tag[u] );
int p = a >> d & 1, q = b >> d & 1;
if ( q ) {
if ( !ch[u][p] ) ch[u][p] = crtnd();
++tag[ch[u][p]];
insert( ch[u][p ^ 1], a, b, d - 1 );
} else {
insert( ch[u][p], a, b, d - 1 );
}
} inline int query( const int u, const int c, const int d ) {
if ( !u ) return 0;
int ret = tag[u];
if ( !~d ) return ret;
return ret + query( ch[u][c >> d & 1], c, d - 1 );
}
} btr; inline void solve( const int l, const int r ) {
if ( l >= r ) return ;
int mid = l + r >> 1, i, j, k;
solve( l, mid ), solve( mid + 1, r );
btr.clear(), i = l, j = mid + 1, k = l;
while ( i <= mid || j <= r ) {
if ( j > r || ( i <= mid && evt[ord[i]].d <= evt[ord[j]].d ) ) {
if ( !evt[ord[i]].id ) {
btr.insert( btr.root, evt[ord[i]].c, evt[ord[i]].d, MAXWID );
}
otmp[k++] = ord[i++];
} else {
if ( evt[ord[j]].id ) {
ans[evt[ord[j]].id] +=
btr.query( btr.root, evt[ord[j]].c, MAXWID );
}
otmp[k++] = ord[j++];
}
}
dtr.clear(), i = mid, j = r;
while ( i >= l || j > mid ) {
if ( j == mid || ( i >= l && evt[ord[i]].d > evt[ord[j]].d ) ) {
if ( !evt[ord[i]].id ) {
dtr.insert( dtr.root, evt[ord[i]].c, MAXWID );
}
--i;
} else {
if ( evt[ord[j]].id ) {
ans[evt[ord[j]].id] +=
dtr.query( dtr.root, evt[ord[j]].c, evt[ord[j]].d, MAXWID);
}
--j;
}
}
rep ( i, l, r ) ord[i] = otmp[i];
} int main() {
n = rint(), q = rint();
rep ( i, 1, n ) {
int a = rint(), b = rint();
evt[++qall] = Event( i, a, b, 0 );
}
rep ( i, 1, q ) {
int l = rint(), r = rint(), c = rint(), d = rint();
evt[++qall] = Event( l - 1, c, d, ( i << 1 ) - 1 );
evt[++qall] = Event( r, c, d, i << 1 );
}
rep ( i, 1, qall ) ord[i] = i;
std::sort( evt + 1, evt + qall + 1 );
solve( 1, qall );
rep ( i, 1, q ) wint( ans[i << 1] - ans[( i << 1 ) - 1] ), putchar( '\n' );
return 0;
}

\(\mathcal{Details}\)

  好久没写这个板块了。

  且不谈考场上能不能解出这道题,给这道题留的思考时间短得明显不合理。一来是策略问题——明明知道难度可能无需,却还骗自己说别人都把 T1 切了然后想了半天;二来,有些不习惯 \(3.5h\) 这种到长不短的比赛时间。

  哎,今后尝试优化考试策略叭。

Solution -「NOIOL-S 2021」「洛谷 P7470」岛屿探险的更多相关文章

  1. 「区间DP」「洛谷P1043」数字游戏

    「洛谷P1043」数字游戏 日后再写 代码 /*#!/bin/sh dir=$GEDIT_CURRENT_DOCUMENT_DIR name=$GEDIT_CURRENT_DOCUMENT_NAME ...

  2. Solution -「JSOI 2019」「洛谷 P5334」节日庆典

    \(\mathscr{Description}\)   Link.   给定字符串 \(S\),求 \(S\) 的每个前缀的最小表示法起始下标(若有多个,取最小的).   \(|S|\le3\time ...

  3. Solution -「洛谷 P4372」Out of Sorts P

    \(\mathcal{Description}\)   OurOJ & 洛谷 P4372(几乎一致)   设计一个排序算法,设现在对 \(\{a_n\}\) 中 \([l,r]\) 内的元素排 ...

  4. Solution -「POI 2010」「洛谷 P3511」MOS-Bridges

    \(\mathcal{Description}\)   Link.(洛谷上这翻译真的一言难尽呐.   给定一个 \(n\) 个点 \(m\) 条边的无向图,一条边 \((u,v,a,b)\) 表示从 ...

  5. Solution -「APIO 2016」「洛谷 P3643」划艇

    \(\mathcal{Description}\)   Link & 双倍经验.   给定 \(n\) 个区间 \([a_i,b_i)\)(注意原题是闭区间,这里只为方便后文描述),求 \(\ ...

  6. 「洛谷4197」「BZOJ3545」peak【线段树合并】

    题目链接 [洛谷] [BZOJ]没有权限号嘤嘤嘤.题号:3545 题解 窝不会克鲁斯卡尔重构树怎么办??? 可以离线乱搞. 我们将所有的操作全都存下来. 为了解决小于等于\(x\)的操作,那么我们按照 ...

  7. 「洛谷3338」「ZJOI2014」力【FFT】

    题目链接 [BZOJ] [洛谷] 题解 首先我们需要对这个式子进行化简,否则对着这么大一坨东西只能暴力... \[F_i=\sum_{j<i} \frac{q_iq_j}{(i-j)^2}-\s ...

  8. 「BZOJ2733」「洛谷3224」「HNOI2012」永无乡【线段树合并】

    题目链接 [洛谷] 题解 很明显是要用线段树合并的. 对于当前的每一个连通块都建立一个权值线段树. 权值线段树处理操作中的\(k\)大的问题. 如果需要合并,那么就线段树暴力合并,时间复杂度是\(nl ...

  9. 「洛谷3870」「TJOI2009」开关【线段树】

    题目链接 [洛谷] 题解 来做一下水题来掩饰ZJOI2019考炸的心情QwQ. 很明显可以线段树. 维护两个值,\(Lazy\)懒标记表示当前区间是否需要翻转,\(s\)表示区间还有多少灯是亮着的. ...

随机推荐

  1. GDB基础知识

    GDB 基础知识 GDB 基础知识 一.简介 支持命令补全功能 GDB 的调用与退出 二.GDB 的基本指令 1. run/r 2. break/b 3. info breakpoints 4. de ...

  2. 从内存管理原理,窥探OS内存管理机制

    摘要:本文将从最简单的内存管理原理说起,带大家一起窥探OS的内存管理机制,由此熟悉底层的内存管理机制,写出高效的应用程序. 本文分享自华为云社区<探索OS的内存管理原理>,作者:元闰子 . ...

  3. 移动端H5选择本地图片

    移动端H5选择本地图片 html://input<input type="file" accept="image/*" capture="cam ...

  4. MCU软件最佳实践——使用printf打印数据

    在mcu上开发应用时,使用串口打印调试信息是最常用的调试手段之一.printf是c标准库提供的函数,可以方便输出格式化的信息.但针对不同的mcu芯片,printf函数要能正常工作,需要做一些移植和适配 ...

  5. JuiceFS v1.0.0 Beta1 发布,加强数据安全能力

    在 JuiceFS 开源一周年之际,我们迎来了首个里程碑版本 JuiceFS v1.0.0 Beta1,并将开源许可从 AGPL v3 修改为 Apache License 2.0. JuiceFS ...

  6. 【小记录】解决链接libcufft_static.a库出现的错误

    程序中使用了 cv::cuda::dft() 函数,需要在链接的时候使用libcufft_static.a这个库.链接出现大量类似错误:error: undefined reference to __ ...

  7. 集合框架-TreeSet-Comparator比较器练习(字符串长度排序)

    1 package cn.itcast.p5.treeset.test; 2 3 import java.util.Iterator; 4 import java.util.TreeSet; 5 6 ...

  8. 多线程概述(好处和弊端)(jvm多线程解析、主线程运行示例)

    1 package multithread; 2 3 /* 4 * 进程:正在进行中的程序(直译). 5 * 6 * 线程:就是进程中一个负责程序执行的控制单元(执行路径). 7 * 一个进程中可以多 ...

  9. Django ORM 多对多操作 使用聚合函数和分组 F查询与Q查询

    创建表 # models.py form django.db import models class Book(models.Model): # 表名book,django会自动使用项目名+我们定义的 ...

  10. 羽夏看Win系统内核—— APC 篇

    写在前面   此系列是本人一个字一个字码出来的,包括示例和实验截图.由于系统内核的复杂性,故可能有错误或者不全面的地方,如有错误,欢迎批评指正,本教程将会长期更新. 如有好的建议,欢迎反馈.码字不易, ...