problem

洛谷链接

solution

定理 若 i<ji<ji<j 且 i,ji,ji,j 联通,则必有 k∈(i,j)k\in(i,j)k∈(i,j) 也与 i,ji,ji,j 联通。

下面给出证明,挺显然的。

  • 若 ai<aja_i<a_jai​<aj​,则一定有 ai<ak∨ak<aja_i<a_k\vee a_k<a_jai​<ak​∨ak​<aj​ 成立。
  • 若 ai>aja_i>a_jai​>aj​,则一定有一个 x<ix<ix<i 满足 ax<ai∧ax<aja_x<a_i\wedge a_x<a_jax​<ai​∧ax​<aj​ 使得 i,ji,ji,j 间接联通。
    • 若 ak<axa_k<a_xak​<ax​,则有 k−jk-jk−j 联通。
    • 若 ax<aka_x<a_kax​<ak​,则有 k−xk-xk−x 联通。

所以一个连通块一定对应的是数组 aaa 的一段连续区间。

也就是说,所有连通块将数组划分成若干个互不相交且并集为整个数组的区间。

考虑相邻两个连通块,假设前一个联通块的左右端点为 l1,r1l_1,r_1l1​,r1​,则后一个联通块的左右端点为 r1+1(l2),r2r_1+1(l_2),r_2r1​+1(l2​),r2​。

当且仅当 min⁡{ai∣i∈[l1,r1]}>max⁡{ai∣i∈[l2,r2]}\min\{a_i|i\in [l_1,r_1]\}>\max\{a_i|i\in[l_2,r_2]\}min{ai​∣i∈[l1​,r1​]}>max{ai​∣i∈[l2​,r2​]} 两个联通块才不会合并。

进一步讲,点 kkk 能够成为一个连通块的分断点,当且仅当 min⁡{ai∣i≤k}>max⁡{ai∣k<i}\min\{a_i|i\le k\}>\max\{a_i|k<i\}min{ai​∣i≤k}>max{ai​∣k<i}。

不妨将 ai≥aka_i\ge a_kai​≥ak​ 的位置设为 111,ai<aka_i<a_kai​<ak​ 的设为 000,将这个新数组表示为 f(k)f(k)f(k),与 kkk 有关。

则发现,当 kkk 为分断点的时候,f(k)f(k)f(k) 的长相一定是 111...11⏟k000...00\underbrace{111...11}_{k}000...00k111...11​​000...00。

换言之,当 kkk 为分断点的时候,f(k)f(k)f(k) 中 ai≠ai+1a_i\neq a_{i+1}ai​​=ai+1​ 的 iii 有且仅有一个。

当然 f(k)f(k)f(k) 的长相有很多种。但如果 kkk 成为分断点那么 f(k)f(k)f(k) 就只能有一种长相。

换个角度讲,令 w=max⁡{ai∣k<i}w=\max\{a_i|k<i\}w=max{ai​∣k<i},将 >w>w>w 的位置设为 111,≤w\le w≤w 的设为 000,将新数组依旧表示为 f(w)f(w)f(w)。

则 f(w)f(w)f(w) 的长相一定也是 111...11⏟k000...00\underbrace{111...11}_{k}000...00k111...11​​000...00。

确定一个满足条件的 www 后的 kkk 也是唯一的。所以没必要枚举断点 kkk,只需要枚举 www 即可。

也就是说,只需要统计有多少个 www 对应的 f(w)f(w)f(w) 长相是这样的,即有且仅有一对相邻的 101010。

为了规避全 000 和全 111,也就是 w=min⁡/max⁡{ai∣i∈[1,n]}w=\min/\max\{a_i|i\in[1,n]\}w=min/max{ai​∣i∈[1,n]} 的情况,这个时候是没有一对 101010 的。

不妨令 a0=∞,an+1=0a_0=∞,a_{n+1}=0a0​=∞,an+1​=0。则满足条件的 www 的 f(w)f(w)f(w) 有且仅有一对相邻的 101010。

以权值 www 为下标建立线段树,记录每个叶子对应 f(x)f(x)f(x) 长相中 101010 的对数。

最后统计多少个位置的对数为 111 即可。

考虑修改 aia_iai​ ,会对 w∈[min⁡{ai−1,ai},max⁡{ai−1,ai})⋃[min⁡{ai,ai+1},max⁡{ai,ai+1})w\in\Big[\min\{a_{i-1},a_i\},\max\{a_{i-1},a_{i}\}\Big)\bigcup\Big[\min\{a_{i},a_{i+1}\},\max\{a_{i},a_{i+1}\}\Big)w∈[min{ai−1​,ai​},max{ai−1​,ai​})⋃[min{ai​,ai+1​},max{ai​,ai+1​}) 造成贡献变化。

例如 w∈[min⁡{ai−1,ai},max⁡{ai−1,ai})w\in\Big[\min\{a_{i-1},a_i\},\max\{a_{i-1},a_{i}\}\Big)w∈[min{ai−1​,ai​},max{ai−1​,ai​}) 时 ai−1,aia_{i-1},a_iai−1​,ai​ 会构成一对 010101,在线段树上将这个区间整体 +1+1+1 即可。

注意到 ai−1,ai+1a_{i-1},a_{i+1}ai−1​,ai+1​ 可能越界,不妨设 a0=lim⁡,an+1=0a_0=\lim,a_{n+1}=0a0​=lim,an+1​=0,那么不管 iii 位置,所有 www 至少都会有 111 对 010101。

线段树很难做到快速查询哪些位置是 111。但是现在所有的 www 的 010101 个数 ≥1\ge 1≥1。

就可以用线段树统计最小值和个数了。当且仅当最小值为 111 的时候再记录答案即可。

当然要注意,只有当前出现在 aaa 数组里的 www,即 w=aiw=a_iw=ai​,才能在线段树中统计代表 www 的叶子节点是否贡献。

code

#include <bits/stdc++.h>
using namespace std;
#define maxn 500005
#define lim 1000001
int n, q;
int a[maxn];
struct node { int sum, tag, cnt; }t[lim + 5 << 2];#define lson now << 1
#define rson now << 1 | 1
#define mid (l + r >> 1)void pushup( int now ) {if( t[lson].sum < t[rson].sum ) t[now].sum = t[lson].sum, t[now].cnt = t[lson].cnt;else if( t[lson].sum > t[rson].sum ) t[now].sum = t[rson].sum, t[now].cnt = t[rson].cnt;elset[now].sum = t[lson].sum, t[now].cnt = t[lson].cnt + t[rson].cnt;
}void pushdown( int now ) {if( t[now].tag ) {t[lson].sum += t[now].tag;t[rson].sum += t[now].tag;t[lson].tag += t[now].tag;t[rson].tag += t[now].tag;t[now].tag = 0;}
}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].sum += x;t[now].tag += x;return;}pushdown( now );modify( lson, l, mid, L, R, x );modify( rson, mid + 1, r, L, R, x );pushup( now );
}void modify( int now, int l, int r, int pos, int x ) {if( l == r ) { t[now].cnt += x; return; }pushdown( now );if( pos <= mid ) modify( lson, l, mid, pos, x );else modify( rson, mid + 1, r, pos, x );pushup( now );
}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].sum == 1 ? t[now].cnt : 0;pushdown( now );return query( lson, l, mid, L, R ) + query( rson, mid + 1, r, L, R );
}void modify( int l, int r, int x ) {if( l == r ) return;if( l > r ) swap( l, r );modify( 1, 0, lim, l, r - 1, x );
}int main() {scanf( "%d %d", &n, &q );for( int i = 1;i <= n;i ++ ) scanf( "%d", &a[i] );a[0] = lim;for( int i = 0;i <= n;i ++ ) {modify( a[i], a[i + 1], 1 );modify( 1, 0, lim, a[i], 1 );}while( q -- ) {int pos, x;scanf( "%d %d", &pos, &x );modify( a[pos - 1], a[pos], -1 );modify( a[pos], a[pos + 1], -1 );modify( 1, 0, lim, a[pos], -1 );a[pos] = x;modify( a[pos - 1], a[pos], 1 );modify( a[pos], a[pos + 1], 1 );modify( 1, 0, lim, a[pos], 1 );printf( "%d\n", query( 1, 0, lim, 1, lim - 1 ) );}return 0;
}

CF1270H Number of Components(线段树)相关推荐

  1. HDU2665 Kth number 可持久化线段树

    题目大意 题目连接 无修改区间第K大数 解题思路 第一次实现了主席树,其实还有两种做法,一种是划分树,WJMZBMR说它是时代的眼泪了,于是我也没想-- 一种是线段树套平衡树--拜托没必要,这道题又没 ...

  2. FZU 2297 Number theory【线段树/单点更新/思维】

    Given a integers x = 1, you have to apply Q (Q ≤ 100000) operations: Multiply, Divide. Input First l ...

  3. Minimum Inversion Number HDU - 1394(权值线段树/树状数组)

    The inversion number of a given number sequence a1, a2, -, an is the number of pairs (ai, aj) that s ...

  4. *【HDU - 4006】 The kth great number(优先队列 or 线段树)

    题干: Xiao Ming and Xiao Bao are playing a simple Numbers game. In a round Xiao Ming can choose to wri ...

  5. Minimum Inversion Number 线段树

    The inversion number of a given number sequence a1, a2, -, an is the number of pairs (ai, aj) that s ...

  6. 【做练习】K-th Number(线段树)线段树的原理

    1. 题目 描述 You are working for Macrohard company in data structures department. After failing your pre ...

  7. hdu1394 Minimum Inversion Number 线段树和树状数组

    题意: 输入一个长度 n 第二行给出长度为n的数组,数组的值刚好为0到n-1这n个数. 然后每次把数组的第一个数放到最后一个,放n-1次,共有n个排列,这n个排列就有n个逆序数,输出这n个逆序数的最小 ...

  8. HDU 1394 Minimum Inversion Number(线段树的单点更新)

    点我看题目 题意 :给你一个数列,a1,a2,a3,a4.......an,然后可以求出逆序数,再把a1放到an后,可以得到一个新的逆序数,再把a2放到a1后边,,,,,,,依次下去,输出最小的那个逆 ...

  9. hdu 4006 The kth great number 线段树/优先队列/set

    题目意思: 有n种操作,I代表插入数据,q代表输出第k大的数. 区间的大数据的操作,基本是用树操作. 这到题目可以用三种方法来做. (1) 线段树 考虑到题目可能有负数,给每个值加500000直接贴代 ...

最新文章

  1. 技术分享连载(十八)
  2. [Google Guava] 1.3-常见Object方法
  3. 99.两个时钟不同步的设备怎么通信?
  4. SAP云平台CloudFoundry编程环境下app router的使用最佳实践
  5. 第13讲nbsp;日期和时间nbsp;EXCEL2010…
  6. 两个小程序大概的了解一下java的线程
  7. 动态数组ArrayList c# 1613536290
  8. HDU2842之斐波那契亚数列变形,动态规划
  9. php 小墙 垃圾评论,关于php过滤垃圾评论
  10. 萌妹子语音在线吹彩虹屁陪你写代码!一个神奇的 VSCode 插件
  11. magento 安装出错 完全解决方案
  12. popup弹出html页面,Popup弹出框绑定添加数据事件(步奏详解)
  13. python:threading.Thread类的使用详解
  14. C语言餐馆点菜系统设计,order-system 使用c语言设计的餐厅点菜系统 - 下载 - 搜珍网...
  15. Join a New Company
  16. SysUtils.Trim、SysUtils.TrimLeft、SysUtils.TrimRight - 删除空格
  17. 作为程序员,你一般用什么软件画流程图时序图和状态图等?
  18. 数据禾|2001年东四盟地区植被类型分布数据
  19. php获取openid提示错误40163,微信网页授权 40163 code已被使用过
  20. ocm认证年薪多少_年薪 100 万在 IT 行业中,属于什么水平 ?

热门文章

  1. 用Python画中国地图(二)
  2. mysql去掉两个最高分_数据分析系列 16/32 | MySQL中子查询与联合查询
  3. Android 页面布局xd,Adobe XD强大的布局系列工具 助你事半功倍
  4. 小猿学python_小猿圈python入门之转行零基础该如何学Python?
  5. java try finally connectoin close_Java SocketChannel類代碼示例
  6. 二面京东,面试官直接问我JVM,我心里一阵暗爽~
  7. html 表格 左侧表头,左侧是表头的JS表格控件(自写,网上没有的)
  8. python怎么安装开发版_python - easy_install的安装和使用
  9. java控制系统音量_Java 控制 Windows 系统音量-Go语言中文社区
  10. anjularjs ajax 调用,AngularJS AJAX调用的服务(AngularJS Ajax Call in Service