CF997E Good Subsegments

给你一个长度为\(n\)的排列 \(P\),定义一段子区间是好的,当且仅当这个子区间内的值构成了连续的一段。例如对于排列\(\{1,3,2\}\),\([1,1],[2,2],[3,3],[2,3],[1,3]\)是好的区间。

共\(q\)次询问,每次询问\(L,R\), 求有多少\(L≤l≤r≤R\),满足\([l,r]\)是好的区间。\(1≤n,q≤1.2×10^5\).


积累一个套路:对于询问区间子序列的信息,可以离线移动右指针,类似扫描线一样计算贡献。

注意到若区间\([l,r]\)满足\(max-min=r-l\),则这个区间是好的区间。

于是在当前指针\(r\)下维护一个\((max-min)-(r-l)\)的最小值以及最小值个数。

然后维护一个答案\(sum\),代表某个区间最小值的贡献(注意这时候不需要维护是不是\(0\),我们只需要在最后累计答案的时候在树根判断就可以了,这个题根一定为\(0\),所以没有判)

但是发现这样不行,我们只是维护了一个右端点为\(r\)的区间的贡献,于是维护一个\(dev\)贡献数组,维护历史出现的最小值出现的贡献。

具体点说,\(dev\)也相当于一个\(tag\),表示这个区间当前的答案需要被贡献到\(sum\),不管它之后怎么样。

然后区间\(max,min\)的相关东西用单调栈额外维护,复杂度是均摊的\(\log n\)

一次操作的大体流程:

  1. 对整个区间打一个右移标记,即区间最小值减\(1\)
  2. 维护单调栈并更新一下\(max,min\)
  3. 打上历史更新\(tag\)
  4. 进行询问

一些细节:初始时每个区间的\(mi\)是它自己的左端点,因为每次是对整颗树的区间打的标记,会减去很多次\(1\),下放标记的时候更新答案看是不是跟自己一样,如果子区间最小值跟自己一样才进行更新。


Code:

#include <cstdio>
#include <algorithm>
#define ll long long
const int N=120010;
using std::min;
int mi[N<<2],ct[N<<2],mitg[N<<2],dev[N<<2];
//最小值,最小值次数,最小值tag,历史贡献tag
ll ans[N],sum[N<<2];
int sta1[N],tot1,sta2[N],tot2;
int n,m,p[N];
struct node
{
int id,l,r;
bool friend operator <(node n1,node n2){return n1.r<n2.r;}
}q[N];
#define ls id<<1
#define rs id<<1|1
void build(int id,int l,int r)
{
mi[id]=l,ct[id]=1;int mid=l+r>>1;
if(l^r) build(ls,l,mid),build(rs,mid+1,r);
}
void addmi(int id,int d){mi[id]+=d,mitg[id]+=d;}
void addde(int id,int d){sum[id]+=1ll*ct[id]*d,dev[id]+=d;}
void updata(int id)
{
mi[id]=min(mi[ls],mi[rs]),ct[id]=0;
ct[id]=mi[id]==mi[ls]?ct[id]+ct[ls]:ct[id];
ct[id]=mi[id]==mi[rs]?ct[id]+ct[rs]:ct[id];
sum[id]=sum[ls]+sum[rs];
}
void pushdown(int id)
{
if(mitg[id]) addmi(ls,mitg[id]),addmi(rs,mitg[id]),mitg[id]=0;
if(dev[id])
{
if(mi[id]==mi[ls]) addde(ls,dev[id]);
if(mi[id]==mi[rs]) addde(rs,dev[id]);
dev[id]=0;
}
}
void change(int id,int L,int R,int l,int r,int d)
{
if(l==L&&r==R){addmi(id,d);return;}
int Mid=L+R>>1;pushdown(id);
if(r<=Mid) change(ls,L,Mid,l,r,d);
else if(l>Mid) change(rs,Mid+1,R,l,r,d);
else change(ls,L,Mid,l,Mid,d),change(rs,Mid+1,R,Mid+1,r,d);
updata(id);
}
ll query(int id,int L,int R,int l,int r)
{
if(l==L&&r==R)return sum[id];
int Mid=L+R>>1;pushdown(id);
if(r<=Mid) return query(ls,L,Mid,l,r);
else if(l>Mid) return query(rs,Mid+1,R,l,r);
else return query(ls,L,Mid,l,Mid)+query(rs,Mid+1,R,Mid+1,r);
}
int main()
{
scanf("%d",&n);
for(int i=1;i<=n;i++) scanf("%d",p+i);
scanf("%d",&m);
for(int i=1;i<=m;i++) scanf("%d%d",&q[i].l,&q[i].r),q[i].id=i;
std::sort(q+1,q+1+m);
build(1,1,n);
for(int j=1,i=1;i<=n;i++)
{
addmi(1,-1);
while(tot1&&p[sta1[tot1]]<=p[i])
{
change(1,1,n,sta1[tot1-1]+1,sta1[tot1],p[i]-p[sta1[tot1]]);
--tot1;
}
sta1[++tot1]=i;
while(tot2&&p[sta2[tot2]]>=p[i])
{
change(1,1,n,sta2[tot2-1]+1,sta2[tot2],p[sta2[tot2]]-p[i]);
--tot2;
}
sta2[++tot2]=i;
addde(1,1);
while(q[j].r==i) ans[q[j].id]=query(1,1,n,q[j].l,q[j].r),++j;
}
for(int i=1;i<=m;i++) printf("%lld\n",ans[i]);
return 0;
}

2018.12.25

CF 997E 解题报告的更多相关文章

  1. 12.27 cf div3 解题报告

    12.27 cf div3 解题报告 wxy.wxy,带上分拉,全场做了个无脑小白 比赛场地 A: T1,跟着模拟就好了 B: sort一遍之后 去除的数一定是a[1]或者a[n] 比较去除谁小就输出 ...

  2. CF 1087解题报告

    cf解题报告 记录一下吧 做出:T1 rating :-97 想起几个月前做不出T1还是有点小搞笑呀2333 T1 双指针+特判 T2 发现k特别小,枚举剩余系 还要判断是否是能被n整除 移项发现可以 ...

  3. CF 1215解题报告

    T1 偶数输出n/2 奇数输出(n-1)/2即可 T2 判断是不是回文 不是直接输出子串 是回文继续判断 如果他前(len+1)/2内没有相同 输出-1 其他的 交换不同字符,输出子串 T3 贪心+二 ...

  4. 冲刺Noip2017模拟赛3 解题报告——五十岚芒果酱

    题1  素数 [问题描述] 给定一个正整数N,询问1到N中有多少个素数. [输入格式]primenum.in 一个正整数N. [输出格式]primenum.out 一个数Ans,表示1到N中有多少个素 ...

  5. CF Round #600 (Div 2) 解题报告(A~E)

    CF Round #600 (Div 2) 解题报告(A~E) A:Single Push 采用差分的思想,让\(b-a=c\),然后观察\(c\)序列是不是一个满足要求的序列 #include< ...

  6. Codeforces Round #382 (Div. 2) 解题报告

    CF一如既往在深夜举行,我也一如既往在周三上午的C++课上进行了virtual participation.这次div2的题目除了E题都水的一塌糊涂,参赛时的E题最后也没有几个参赛者AC,排名又成为了 ...

  7. Mutual Training for Wannafly Union #1解题报告

    ---恢复内容开始--- q神等人组织的vjudge上的多校训练,题目基本上都来自于CF,#1是上周进行的,参加后感觉收获很多,因为上周准备期中比较忙,解题报告现在补上. 比赛地址(兼题目地址) A题 ...

  8. Codeforces Round #378 (Div. 2) D题(data structure)解题报告

    题目地址 先简单的总结一下这次CF,前两道题非常的水,可是第一题又是因为自己想的不够周到而被Hack了一次(或许也应该感谢这个hack我的人,使我没有最后在赛后测试中WA).做到C题时看到题目情况非常 ...

  9. Codeforces Round #277.5 解题报告

    又熬夜刷了cf,今天比正常多一题.比赛还没完但我知道F过不了了,一个半小时贡献给F还是没过--应该也没人Hack.写写解题报告吧= =. 解题报告例如以下: A题:选择排序直接搞,由于不要求最优交换次 ...

随机推荐

  1. Siki_Unity_3-7_AssetBundle从入门到掌握

    Unity 3-7 AssetBundle从入门到掌握 任务1&2&3:课程介绍 AssetBundle -- 用于资源的更新 为了之后的xLua (Lua热更新的框架)打下基础 任务 ...

  2. C++ 学习笔记 变量和基本类型(一)

    C++ 学习笔记 一.变量和基本类型概述 类型是所有程序的基础.类型告诉我们数据代表什么意思以及可以对数据执行哪些操作. c++基本类型: 字符型 整型 浮点型 c++ 还提供了可用于自定义数据类型的 ...

  3. windows 平台安装 ffmpeg

    一.从https://ffmpeg.zeranoe.com/builds/中下载ffmpeg的static版本: 二.将下载下来的“ffmpeg-4.0.2-win64-static.zip”解压到任 ...

  4. webpack构建Vue项目引入jQ时发生“'$' is defined but never used”的处理

    今天公司需要新建个数据后台,就按照查到的方法构建了Vue框架的项目,引入jQ.bootstrap时,按照在线方法配置,发现 main.js 里的引用jQ一直显示红标,没多想,在按照网上配置完后,npm ...

  5. 20180711-统计PDB中的蛋白质种类、膜蛋白文件个数及信息等

    20180710完成这份工作.简单,但是完成了还是很开心.在我尝试如何使用pickle保存数据后,尝试保存PDB文件中“HEADER”中的信息.文件均保存于实验室服务器(97.73.198.168)/ ...

  6. Bing词典vs有道词典比对测试报告——功能篇之核心功能

    必应词典vs有道词典 核心功能对比 从应用的UI布局来看,这两款软件的功能如下: 相同 不同 必应词典 词典.例句.翻译 百科 有道词典 词典.例句.翻译 应用 就词典类软件来说,词典是最核心的功能. ...

  7. wcf的DataContractAttribute与DataMenmberAttribute

    文章:序列化和反序列化的几种方式(DataContractSerializer)(二) 介绍了序列化控制细节.哪些字段可以序列化,序列化后这些字段的名字.

  8. IHttpModule理解-知识补充

    文章:IHttpModule的那些事 可以自定义类实现IHttpModule接口,然后实现接口方法Init,Init方法可以得到HttpApplication 的实例化对象. 然后给对象的事件的注册各 ...

  9. 标头 header()函数的用法

    头 (header) 是服务器以 HTTP 协议传 HTML 资料到浏览器前所送出的字串,在标头与 HTML 文件之间尚需空一行分隔. 范例一: 本例使浏览器重定向到 PHP 的官方网站. <? ...

  10. CANOpen学习指南

    对于初学者,相对于其他总线的资料来说,在国内CANOpen的资料并不多.而且并不是所有资料都适合初学者看的.这里给出一些建议,对CANOpen感兴趣的,可以参考一下学习的顺序. 前提:需要对CAN总线 ...