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. STM32中操作寄存器GPIOB_CRL &= ~( 0x0F<< (4*0))与GPIOB_CRL &=~(0x0F)之间有什么区别吗?

    没有区别,作用相同.只是这样写便于修改和沿用. 对于只用到PB0端口的程序~(0x0f << (4*0)) 和~0x0f没有区别.0x0f <<(4*N) 就是 向左 移动N个 ...

  2. Golang通脉之面向对象

    面向对象的三大特征: 封装:隐藏对象的属性和实现细节,仅对外提供公共访问方式 继承:使得子类具有父类的属性和方法或者重新定义.追加属性和方法等 多态:不同对象中同种行为的不同实现方式 Go并不是一个纯 ...

  3. 【数据结构与算法Python版学习笔记】图——基本概念及相关术语

    概念 图Graph是比树更为一般的结构, 也是由节点和边构成 实际上树是一种具有特殊性质的图 图可以用来表示现实世界中很多有意思的事物,包括道路系统.城市之间的航班.互联网的连接,甚至是计算机专业的一 ...

  4. 改善深层神经网络-week3编程题(Tensorflow 实现手势识别 )

    TensorFlow Tutorial Initialize variables Start your own session Train algorithms Implement a Neural ...

  5. python png图片生成gif

    有时候写代码就是这样别人把代码写好你在后面加一个句号就行了 我很懒不想写成函数,你自己来吧.有注释就不错了 这个依赖一个图像处理库pillow,轮子就是轮他不是车 import imageio imp ...

  6. Java:多线程计数

    Java:多线程计数 本笔记是根据bilibili上 尚硅谷 的课程 Java大厂面试题第二季 而做的笔记 1. CountDownLatch 概念 让一些线程阻塞直到另一些线程完成一系列操作才被唤醒 ...

  7. 解决git clone慢问题

    解决git clone慢 关于Git克隆或是上传代码龟速的问题真是让人很恼火,这里对于网上的两种解决方案进行摘录. 利用码云克隆github项目 亲测有效 进入码云,新建一个仓库: 在创建的最后选择导 ...

  8. 使用Mybatis的TypeHandler加解密数据

    使用Mybatis的TypeHandler加解密数据 一.背景 二.解决方案 三.需求 四.实现思路 1.编写一个实体类,凡是此实体类的数据都表示需要加解密的 2.编写一个加解密的`TypeHandl ...

  9. 字符串与模式匹配算法(五):BMH算法

    一.BMH算法介绍 在BM算法的实际应用中,坏字符偏移函数的应用次数要远远超过好后缀偏移函数的应用次数,坏字符偏移函数在匹配过程中起着移动指针的主导作用.在实际匹配过程,只是用坏字符偏移函数也非常有效 ...

  10. 有关fgetc配合feof逐行读取文件最后一行读取两遍的错觉?

    最近在做一个wifiap设置的接口,用户首先获取到当前wifi 热点的ssid 和pwd,然后修改,保存. 获取信息的时候是fopen对应的hostapd.conf文件,逐行读取,查找匹配的参数. 修 ...