Codeforces 题目传送门 & 洛谷题目传送门

感觉这个 *2900 并不难啊,为什么我没想出来呢 awa

顺便膜拜 ycx 一眼秒掉此题 %%%

首先碰到这类题有两种思路,一是枚举两个区间,显然这个思路是不可行的,因为这个思路有四个自由变量 \(l_1,r_1,l_2,r_2\),并且还会出现重复计算的情况,非常棘手。二是注意到 \([l_1,r_1]\cup[l_2,r_2]\) 是一段连续的区间,故考虑枚举这段区间值域的左右端点 \([l,r]\),我们只需统计有多少个区间 \([l,r]\) 满足值在 \([l,r]\) 中的数组成连续段的个数 \(\le 2\) 即可。

我们考虑记录 \(f(l,r)\) 表示值在 \([l,r]\) 中的数组成连续段的个数,\(S(l,r)\) 表示 \(a_p\in[l,r]\) 的 \(p\) 组成的集合。考虑动态枚举 \(r\),建一棵线段树,下标为 \(l\) 的位置实时维护 \([l,r]\) 的个数。考虑右端点从 \(r\) 移到 \(r-1\) 会对 \(f(l,r)\) 的值产生什么影响,假设 \(a_p=r\),首先显然 \(\forall l\le r\),\(p\in S(l,r)\),故我们先假设 \(p\) 单独一段,即令 \([1,r]\) 的值加 \(1\)。其次如果 \(a_{p-1}<r\),那么对于 \(\forall l\le a_{p-1}\),\(p,p-1\) 必定都属于 \(S(l,r)\),因此我们可以将它们合并起来,\(f(l,r)\) 的值减 \(1\),\(a_{p+1}\) 也同理。以上操作都可以通过线段树区间加在 \(\mathcal O(\log n)\) 的时间内搞定。

最后考虑怎样统计答案,显然对于固定的右端点 \(r\),符合条件的 \(l\) 个数即为满足 \(l\in[1,r],f(l,r)\le 2\) 的 \(l\) 个数。直接统计是比较麻烦的,不过这里有一个我见过 N 次的套路,显然 \(\forall l\le r,f(l,r)>0\),因此区间 \([1,r]\) 中最小值 \(\ge 1\),次小值 \(\ge 2\),故我们只需维护最小值、最小值个数、次小值、次小值个数,查询时访问对应区间,如果最小值 \(\le 2\) 答案加上最小值个数,如果次小值 \(\le 2\) 答案加上次小值个数。节点合并就将左右儿子的最小值、次小值放到一个长度为 \(4\) 的数组里排个序乱搞搞即可。

时间复杂度 \(\mathcal O(n\log n)\)。

const int MAXN=3e5;
const int INF=0x3f3f3f3f;
int n,p[MAXN+5],pos[MAXN+5];
struct node{int l,r,lz;pii fst,snd;} s[MAXN*4+5];
void pushup(int k){
static pii p[4];
p[0]=s[k<<1].fst;p[1]=s[k<<1].snd;
p[2]=s[k<<1|1].fst;p[3]=s[k<<1|1].snd;
sort(p,p+4);s[k].fst=mp(p[0].fi,0);int cur=0;
while(p[cur].fi==p[0].fi) s[k].fst.se+=p[cur].se,cur++;
s[k].snd=mp(p[cur].fi,0);
while(p[cur].fi==s[k].snd.fi) s[k].snd.se+=p[cur].se,cur++;
}
void build(int k,int l,int r){
s[k].l=l;s[k].r=r;if(l==r){s[k].fst=mp(0,1);s[k].snd=mp(INF,0);return;}
int mid=l+r>>1;build(k<<1,l,mid);build(k<<1|1,mid+1,r);pushup(k);
}
void pushdown(int k){
if(s[k].lz){
s[k<<1].fst.fi+=s[k].lz;s[k<<1].snd.fi+=s[k].lz;s[k<<1].lz+=s[k].lz;
s[k<<1|1].fst.fi+=s[k].lz;s[k<<1|1].snd.fi+=s[k].lz;s[k<<1|1].lz+=s[k].lz;
s[k].lz=0;
}
}
void modify(int k,int l,int r,int x){
if(l<=s[k].l&&s[k].r<=r){
s[k].fst.fi+=x;s[k].snd.fi+=x;s[k].lz+=x;
return;
} pushdown(k);int mid=s[k].l+s[k].r>>1;
if(r<=mid) modify(k<<1,l,r,x);
else if(l>mid) modify(k<<1|1,l,r,x);
else modify(k<<1,l,mid,x),modify(k<<1|1,mid+1,r,x);
pushup(k);
}
int query(int k,int l,int r){
if(l<=s[k].l&&s[k].r<=r){
int ret=0;
if(s[k].fst.fi<=2) ret+=s[k].fst.se;
if(s[k].snd.fi<=2) ret+=s[k].snd.se;
return ret;
} pushdown(k);int mid=s[k].l+s[k].r>>1;
if(r<=mid) return query(k<<1,l,r);
else if(l>mid) return query(k<<1|1,l,r);
else return query(k<<1,l,mid)+query(k<<1|1,mid+1,r);
}
int main(){
scanf("%d",&n);ll ans=0;build(1,1,n);
for(int i=1;i<=n;i++) scanf("%d",&p[i]),pos[p[i]]=i;
for(int i=1;i<=n;i++){
modify(1,1,i,1);
if(pos[i]!=1&&p[pos[i]-1]<i) modify(1,1,p[pos[i]-1],-1);
if(pos[i]!=n&&p[pos[i]+1]<i) modify(1,1,p[pos[i]+1],-1);
if(i!=1) ans+=query(1,1,i-1);
} printf("%lld\n",ans);
return 0;
}

Codeforces 193D - Two Segments(线段树)的更多相关文章

  1. codeforces 652D . Nested Segments 线段树

    题目链接 我们将线段按照右端点从小到大排序, 如果相同, 那么按照左端点从大到小排序. 然后对每一个l, 查询之前有多少个l比他大, 答案就是多少.因为之前的r都是比自己的r小的, 如果l还比自己大的 ...

  2. Buses and People CodeForces 160E 三维偏序+线段树

    Buses and People CodeForces 160E 三维偏序+线段树 题意 给定 N 个三元组 (a,b,c),现有 M 个询问,每个询问给定一个三元组 (a',b',c'),求满足 a ...

  3. CodeForces 877E DFS序+线段树

    CodeForces 877E DFS序+线段树 题意 就是树上有n个点,然后每个点都有一盏灯,给出初始的状态,1表示亮,0表示不亮,然后有两种操作,第一种是get x,表示你需要输出x的子树和x本身 ...

  4. [Codeforces 1197E]Culture Code(线段树优化建图+DAG上最短路)

    [Codeforces 1197E]Culture Code(线段树优化建图+DAG上最短路) 题面 有n个空心物品,每个物品有外部体积\(out_i\)和内部体积\(in_i\),如果\(in_i& ...

  5. [Codeforces 1199D]Welfare State(线段树)

    [Codeforces 1199D]Welfare State(线段树) 题面 给出一个长度为n的序列,有q次操作,操作有2种 1.单点修改,把\(a_x\)修改成y 2.区间修改,把序列中值< ...

  6. [Codeforces 316E3]Summer Homework(线段树+斐波那契数列)

    [Codeforces 316E3]Summer Homework(线段树+斐波那契数列) 顺便安利一下这个博客,给了我很大启发(https://gaisaiyuno.github.io/) 题面 有 ...

  7. Codeforces Round #337 (Div. 2) D. Vika and Segments 线段树扫描线

    D. Vika and Segments 题目连接: http://www.codeforces.com/contest/610/problem/D Description Vika has an i ...

  8. Codeforces Round #337 (Div. 2) D. Vika and Segments 线段树 矩阵面积并

    D. Vika and Segments     Vika has an infinite sheet of squared paper. Initially all squares are whit ...

  9. Codeforces Round #337 (Div. 2) D. Vika and Segments (线段树+扫描线+离散化)

    题目链接:http://codeforces.com/contest/610/problem/D 就是给你宽度为1的n个线段,然你求总共有多少单位的长度. 相当于用线段树求面积并,只不过宽为1,注意y ...

随机推荐

  1. SharkCTF2021 BabyGame

    web类题. 访问题给页面,页面里没啥信息.抓包,发现: 访问它,发现是一个游戏. F12之后看调试器里的js代码,发现: console.log("balabalabala"); ...

  2. [技术博客] 软工-Ruby on Rails 后端开发总结分享

    [技术博客] 软工-Ruby on Rails 后端开发总结分享 在这次软件编写中,我们的后端使用了Ruby on Rails (RoR)框架. Rails框架是用Ruby编写的.这意味着当我们为Ru ...

  3. CentOS 7:快速安装Tomcat7.x

    到官网下载对应的压缩包,CentOS 7的Tomcat下载地址:http://tomcat.apache.org/download-70.cgi,下载后传进服务器中并放在你指定的位置上. 或者使用命令 ...

  4. 小白自制Linux开发板 十. NES游戏玩起来

    本篇基于我们制作的Debian文件系统而展开,而且我们这会玩一些高级的操作方式--用我们的小电脑进行程序编译.   所以本篇操作全部都在我们个的开发板上完成.   1. 开发环境搭建 首先安装gcc, ...

  5. Linux上Qt旋转显示

    对于嵌入式设备来说用于显示的LCD总是千奇百怪,比如说明明是一个竖屏,但是客户却要当横屏使用,也就是意味着我们需要将整个屏幕上显示的内容旋转90度或者270度. 这个操作对于Android系统来说相当 ...

  6. 转载:10G以太网光口与Aurora接口回环实验

    10G以太网光口与高速串行接口的使用越来越普遍,本文拟通过一个简单的回环实验,来说明在常见的接口调试中需要注意的事项.各种Xilinx FPGA接口学习的秘诀:Example Design.欢迎探讨. ...

  7. Forest v1.5.12 发布,声明式 HTTP 框架,已超过 1.6k star

    Forest介绍 Forest 是一个开源的 Java HTTP 客户端框架,它能够将 HTTP 的所有请求信息(包括 URL.Header 以及 Body 等信息)绑定到您自定义的 Interfac ...

  8. spark structured-streaming 最全的使用总结

    一.spark structured-streaming  介绍 我们都知道spark streaming  在v2.4.5 之后 就进入了维护阶段,不再有新的大版本出现,而且 spark strea ...

  9. ONVIF客户端中预置位设置代码实现过程

    simpleOnvif的功能:提供支持Windows.Linux.arm.Android.iOS等各种平台的SDK库,方便集成,二次开发 之前跟大家分享了我们安徽思蔷信息科技的simpleOnvif的 ...

  10. 【python+postman接口自动化测试】(1)网络基础知识

    一.IP地址 就像每个人都有一个身份证号码 IP地址是IP协议提供的一种统一的地址格式,它为互联网上的每一个网络和每一台主机分配一个逻辑地址. 查看IP命令: Windows: ipconfig Li ...