problem

给定数组 l,rl,rl,r。求有多少个非空集合 SSS,满足 ∀i,j∈Sli≤j≤ri\forall_{i,j\in S}\ l_i\le j\le r_i∀i,j∈S​ li​≤j≤ri​。

集合内对于任意一个点而言,其余点均能被自己的范围覆盖到。

n≤2e5n\le 2e5n≤2e5。

solution

分享一下考场心路历程:考试是分了五个部分分的。

第一个部分分直接 2n2^n2n 暴枚,很快拿下。

第二个部分分 n≤2000n\le 2000n≤2000,一看就是 n2n^2n2 算法,我就想到了固定集合选取点的最左最右点,然后看有多少个点满足 li≤L∧R≤ri∧L≤i≤Rl_i\le L\wedge R\le r_i\wedge L\le i\le Rli​≤L∧R≤ri​∧L≤i≤R,天哪太多的偏序关系了,我直接抡 KD-tree\text{KD-tree}KD-tree,好家伙大样例虽然对了却要跑 6s6s6s,试问谁遭得住?

第三个部分分 ri−li≤10r_i-l_i\le 10ri​−li​≤10。我就只枚举最左点,然后暴搜/Hash\text{Hash}Hash 集合个数,不超过 2102^{10}210,算出来大约 2e82e82e8 但肯定跑不满。一看样例全过。(测评最后结果 wa\text{wa}wa 了,但这不重要了)

第四个部分分,5e45e45e4 可能是分块吧。对我没有太多帮助。

第五个部分分,就是最大的范围了。

由第二个部分的枚举 l,rl,rl,r 我突然想到了前不久狂做 LCT\text{LCT}LCT 的一类连通性题。全都是枚举了右端点然后用线段树上的节点做左端点,并用线段树维护答案个数。

这里我想类比做法:蒋所有 [li,ri][l_i,r_i][li​,ri​] 全挂到 rir_iri​ 点下。

枚举 iii 做右端点,然后线段树上的节点做左端点。

新右端点会对 [li,i][l_i,i][li​,i] 都提供 111 的个数(答案是 2cnt2^\text{cnt}2cnt,每个数选或不选)

当 iii 右移一位的时候,就要去掉所有 rj=ir_j=irj​=i 的 jjj 曾经的贡献。

然后,然后,我发现强制左右端点后虽然不会算重,但是应该算的是 2cnt−22^{cnt-2}2cnt−2(去掉左右端点选和不选的考虑)

结果这样又会影响我线段树的标记下放,那我的线段树不是废了?!!

最后不管是在线段树上维护个数还是直接维护贡献都无法正确避免 −2-2−2 带来的影响,在主函数内我也无法去掉。我就直接开始摆烂了。。。

结果下午过来,给小同志讲了一遍后没讲懂,被她质疑的我就仔细想了一下,突然想到了貌似大概也许可以这么来,重构一遍直接过!心中草泥马奔腾。。。

从左到右枚举集合的右端点 rrr(最大的点)。

然后线段树上的节点 lll 强制是集合的左端点,且维护的信息是 l,rl,rl,r 做左右端点时的答案。

考虑统计右端点为 iii 的答案。

首先要激活线段树上的 iii 节点,初始化为 111,代表 [i,i][i,i][i,i] 集合。

然后统计线段树上 [li,i][l_i,i][li​,i] 区间的答案。

接下来 iii 要右移 +1+1+1,我们需要重新修改维护线段树上的信息。

  • 对区间 [li,i−1][l_i,i-1][li​,i−1] 进行区间 ×2\times 2×2。

    表示当这些区间中的节点为集合左端点时,iii 是合法互达备选点,存在选和不选的方案考虑。

    但不能对 iii 也进行 ×2\times 2×2,理由在心路历程后面提到,它是被强制了的。

  • 对所有 rj=ir_j=irj​=i 的 jjj,从 i+1i+1i+1 开始当右端点后,jjj 就不可能再到达集合的右端点了,再也不能成为合法互达备选点,所以要把 jjj 之前提供的贡献全都去掉。

    要进行 [lj,j−1][l_j,j-1][lj​,j−1] 区间 /2/2/2,以及节点 jjj 的直接赋 000。(这样 jjj 就在也不可能成为集合左端点被纳入贡献了)

时间复杂度 O(nlog⁡n)O(n\log n)O(nlogn)。

code

#include <bits/stdc++.h>
using namespace std;
#define maxn 200005
#define int long long
#define mod 998244353namespace SGT {struct node { int cnt, tag; }t[maxn << 2];#define lson now << 1#define rson now << 1 | 1#define mid  (l + r >> 1)void build( int now, int l, int r ) {t[now].tag = 1;if( l == r ) return;build( lson, l, mid );build( rson, mid + 1, r );}void pushdown( int now ) {if( t[now].tag == 1 ) return;( t[lson].tag *= t[now].tag ) %= mod;( t[rson].tag *= t[now].tag ) %= mod;( t[lson].cnt *= t[now].tag ) %= mod;( t[rson].cnt *= t[now].tag ) %= mod;t[now].tag = 1;}void modify( int now, int l, int r, int p, int x ) {if( l == r ) { t[now].cnt = x ? 1 : 0; return; }pushdown( now );if( p <= mid ) modify( lson, l, mid, p, x );else modify( rson, mid + 1, r, p, x );t[now].cnt = ( t[lson].cnt + t[rson].cnt ) % mod;}void modify( int now, int l, int r, int L, int R, int x ) {if( R < l or r < L ) return;if( L <= l and r <= R ) { ( t[now].cnt *= x ) %= mod;( t[now].tag *= x ) %= mod;return;}pushdown( now );modify( lson, l, mid, L, R, x );modify( rson, mid + 1, r, L, R, x );t[now].cnt = ( t[lson].cnt + t[rson].cnt ) % mod;}int query( int now, int l, int r, int L, int R ) {if( R < l or r < L ) return 0;if( L <= l and r <= R ) return t[now].cnt;pushdown( now );return query( lson, l, mid, L, R ) + query( rson, mid + 1, r, L, R );}
}int n;
int l[maxn], r[maxn];
vector < int > G[maxn];
signed main() {scanf( "%lld", &n );for( int i = 1;i <= n;i ++ ) scanf( "%lld", &l[i] );for( int i = 1;i <= n;i ++ ) scanf( "%lld", &r[i] );for( int i = 1;i <= n;i ++ ) G[r[i]].push_back( i );SGT :: build( 1, 1, n ); //线段树上强制节点为选取集合最小值int ans = 0;int inv = mod + 1 >> 1;for( int i = 1;i <= n;i ++ ) { //强制选取的集合最大值SGT :: modify( 1, 1, n, i, 1 ); //把i激活 初始化1( ans += SGT :: query( 1, 1, n, l[i], i ) ) %= mod;SGT :: modify( 1, 1, n, l[i], i - 1, 2 ); //对于最小值属于[l[i],i-1]的点 会有一个新的i可以互达for( int j : G[i] ) {SGT :: modify( 1, 1, n, l[j], j - 1, inv );SGT :: modify( 1, 1, n, j, 0 );}}printf( "%lld\n", ans );return 0;
}

互达的集合(线段树)相关推荐

  1. [权值线段树]魔道研究

    题目描述 "我希望能使用更多的魔法.不对,是预定能使用啦.最终我要被大家称呼为大魔法使.为此我决定不惜一切努力." --<The Grimoire of Marisa> ...

  2. 【线段树 集合hash】bzoj4373: 算术天才⑨与等差数列

    hash大法好(@ARZhu):大数相乘及时取模真的是件麻烦事情 Description 算术天才⑨非常喜欢和等差数列玩耍. 有一天,他给了你一个长度为n的序列,其中第i个数为a[i]. 他想考考你, ...

  3. 【拓扑 字符串还原 + 线段树维护】奇洛金卡达(father)

    奇洛金卡达(father) Description 阿良良木历将要迎来人生(不,是吸血鬼生涯)的第三次战斗--与身为 人类的奇洛金卡达在直江津高中的操场solo,以取回Heartunderblade ...

  4. 2018.3.15校内互测总结-点分治-线段树

    这是曾来过咱们学校集训的一位大神出的~ T1 题目大意 给出一棵带边权的无根树,求树上前$k$大的路径的长度. $1 \leq n \leq 200000$ 题解 想了一上午点分治,却发现只会$O(n ...

  5. 线段树/树状数组问题 | 问题集合

    写在前面 线段树代码实在冗长,于是乎能用树状数组直接搞的就懒得打线段树了(:溜 1.P2620[QZYZ] 校门外的树 描述 Description 校门外有很多树,有苹果树,香蕉树,有会扔石头的,有 ...

  6. 主席树——多棵线段树的集合

    主席树: (不要管名字) 我们有的时候,会遇到很多种情况,对于每一种情况,都需要通过线段树的操作实现. 碰巧的是,相邻两种情况下的线段树的差异不大.(总体的差异次数是O(N)级别的,均摊就是O(常数) ...

  7. 【线段树分治 线性基】luoguP3733 [HAOI2017]八纵八横

    不知道为什么bzoj没有HAOI2017 题目描述 Anihc国有n个城市,这n个城市从1~n编号,1号城市为首都.城市间初始时有m条高速公路,每条高速公路都有一个非负整数的经济影响因子,每条高速公路 ...

  8. [2021-07-19 内测NOIP] 操作(状压DP),异或(字典树),等级(线段树),矩阵(DP)

    [2021-07-19 内测] NOIP 操作 description solution code 异或 description solution code 等级 description soluti ...

  9. BZOJ 5394 [Ynoi2016]炸脖龙 (线段树+拓展欧拉定理)

    题目大意:给你一个序列,需要支持区间修改,以及查询一段区间$a_{i}^{a_{i+1}^{a_{i+2}...}}mod\;p$的值,每次询问的$p$的值不同 对于区间修改,由线段树完成,没什么好说 ...

最新文章

  1. Atitit 为什么网络会有延时 电路交换与分组交换的区别
  2. PMBOK第七版,通往项目管理的新地图
  3. 分享一些Java开发人员在编程中最容易踩雷的地方!
  4. 【转】linux tar.gz zip 解压缩 压缩命令
  5. redis5种数据结构讲解及使用场景
  6. 反射+javacsv+scv文件构建资源获取
  7. Flutter StreamController 异步通信、Stream 流异步通信
  8. 杭电2112HDU Today(map 最短路径)
  9. OCR方向目前最火的repo,绝绝子!
  10. 开好会议有诀窍------(转)
  11. java 控制台输出到gui_java – 如何将类似窗口的“控制台”添加到GUI?
  12. 用例图中三种关系详解(转)
  13. 7-11 mmh学长的万能日历 (20分)
  14. 如何理解Beta分布和Dirichlet分布?
  15. PCI/PCIe的学习笔记
  16. PDF页面旋转怎么操作
  17. 轻松在线绘制进化树和增加热图注释
  18. C#设计模式(6)——原型模式(Prototype Pattern)
  19. 常用DC-DC;AC-DC电源芯片
  20. CMake中foreach的使用

热门文章

  1. android ifw 启动广告,使用 IFW 完全控制 Android 应用行为 | 实用技巧
  2. 华为二面!!!被问常用API,这也太偏门了吧,我秀了一波hhhh~
  3. 求职华为,被问观察者模式,从没有这种体验!!!
  4. ubuntu php7.4,在Ubuntu 18.04/19.04/16.04版本上安装PHP 7.4的简单方法
  5. 机器学习之模型——保存与加载
  6. 买卖股票类问题动态规划解法(Leetcode题解-Python语言)
  7. C++实现AOE网中的关键路径算法(邻接表存储)
  8. C++实现拓扑排序(vector模拟邻接表存储,优先队列实现)
  9. [C++11]字符串原始字面量
  10. 扫地机器人隔板_【扫地机器人使用】_摘要频道_什么值得买