Portal

题意:

给出排列 \(p_1,p_2,p_3,\dots,p_n\),定义一个区间 \([l,r]\) 是好的当且仅当 \(p_l,p_{l+1},p_{l+2},\dots,p_r\) 包含了连续的 \(r-l+1\) 个数。

\(q\) 次询问,每次询问给出两个数 \(l,r\),求满足 \(l\leq x\leq y\leq r\) 且 \([x,y]\) 为好区间的 \((x,y)\) 的个数。

\(n,q\leq 1.2\times 10^5\)

首先把“好区间”的定义翻译成人话就是 \((mx-mn)-(r-l)=0\)

不难想到将询问离线下来,记录到右端点上,然后用类似扫描线的方法求解。

动态地枚举右端点 \(r\),建一棵线段树,线段树上下标为 \(l\) 的位置记录区间 \([l,r]\) 的 \((mx-mn)-(r-l)\) 的值。

当右端点从 \(r-1\) 变为 \(r\) 的时候,单调栈(sb 了 1/2)维护区间最大值和最小值的变化。同时在线段树上下标在 \([1,r-1]\) 中的位置全部减 \(1\):\(-(r-1-l)\) 变为 \(-(r-l)\)。以 \(r\) 为右端点的“好区间”的个数就是线段树上值为 \(0\) 的个数。注意到 线段树上位置为 \(r\) 的数总是 \(0\)(即区间 \([r,r]\) 永远是好区间),所以最小值的个数就是线段树上值为 \(0\) 的个数。

但此题要求的是右端点在 \([l,r]\) 之间的好区间的个数,而不仅仅是右端点为 \(r\) 的好区间个数。(sb 了 2/2)所以我们线段树上新维护两个值:\(sum\) 和 \(cnt\)。\(sum\) 表示线段树上 \([l,r]\) 这个区间历史上出现了多少次 \(0\),\(cnt\) 表示当前区间的 \(0\) 的个数要累加进答案多少次,i.e.,如果当前区间有 \(x\) 个 \(0\),那么就要令 \(sum+=x\times cnt\)。当我们 pushdown 的时候,如果它左儿子的最小值等于当前区间的最小值,就把这个 \(cnt\) 标记传给它的左儿子。右儿子也同理。每次移动右端点的时候将整颗线段树的 \(cnt\) 值加 \(1\)。然后查询区间 \([l,r]\) 的 \(sum\) 值之和就可以了。 注意到我们修改一个区间的时候是一路 pushdown 下来的,这意味着没有访问到的区间中 \(0\) 的个数不会发生变化,故其满足可乘性,所以这样搞没有问题。

时间复杂度线性对数。

  1. #include <bits/stdc++.h>
  2. using namespace std;
  3. #define fi first
  4. #define se second
  5. #define fz(i,a,b) for(int i=a;i<=b;i++)
  6. #define fd(i,a,b) for(int i=a;i>=b;i--)
  7. #define ffe(it,v) for(__typeof(v.begin()) it=v.begin();it!=v.end();it++)
  8. #define fill0(a) memset(a,0,sizeof(a))
  9. #define fill1(a) memset(a,-1,sizeof(a))
  10. #define fillbig(a) memset(a,63,sizeof(a))
  11. #define pb push_back
  12. #define ppb pop_back
  13. #define mp make_pair
  14. template<typename T1,typename T2> void chkmin(T1 &x,T2 y){if(x>y) x=y;}
  15. template<typename T1,typename T2> void chkmax(T1 &x,T2 y){if(x<y) x=y;}
  16. typedef pair<int,int> pii;
  17. typedef long long ll;
  18. template<typename T> void read(T &x){
  19. x=0;char c=getchar();T neg=1;
  20. while(!isdigit(c)){if(c=='-') neg=-1;c=getchar();}
  21. while(isdigit(c)) x=x*10+c-'0',c=getchar();
  22. x*=neg;
  23. }
  24. const int MAXN=1.2e5;
  25. int n,qu,a[MAXN+5];ll ans[MAXN+5];
  26. struct Query{int l,r;} q[MAXN+5];
  27. vector<int> qv[MAXN+5];
  28. struct node{
  29. int l,r,mn,num,add_lz;
  30. ll sum,cnt_lz;
  31. } s[MAXN*4+5];
  32. void pushup(int k){
  33. s[k].mn=min(s[k<<1].mn,s[k<<1|1].mn);
  34. s[k].num=(s[k<<1].num)*(s[k<<1].mn==s[k].mn)+(s[k<<1|1].num)*(s[k<<1|1].mn==s[k].mn);
  35. s[k].sum=s[k<<1].sum+s[k<<1|1].sum;
  36. }
  37. void pushdown(int k){
  38. if(s[k].add_lz){
  39. s[k<<1].add_lz+=s[k].add_lz;s[k<<1].mn+=s[k].add_lz;
  40. s[k<<1|1].add_lz+=s[k].add_lz;s[k<<1|1].mn+=s[k].add_lz;
  41. s[k].add_lz=0;
  42. }
  43. if(s[k].cnt_lz){
  44. if(s[k<<1].mn==s[k].mn) s[k<<1].cnt_lz+=s[k].cnt_lz,s[k<<1].sum+=s[k].cnt_lz*s[k<<1].num;
  45. if(s[k<<1|1].mn==s[k].mn) s[k<<1|1].cnt_lz+=s[k].cnt_lz,s[k<<1|1].sum+=s[k].cnt_lz*s[k<<1|1].num;
  46. s[k].cnt_lz=0;
  47. }
  48. }
  49. void build(int k,int l,int r){
  50. s[k].l=l;s[k].r=r;if(l==r){s[k].num=1;return;}
  51. int mid=(l+r)>>1;build(k<<1,l,mid);build(k<<1|1,mid+1,r);
  52. pushup(k);
  53. }
  54. void modify(int k,int l,int r,int x){
  55. if(l>r) return;
  56. if(l<=s[k].l&&s[k].r<=r){s[k].mn+=x;s[k].add_lz+=x;return;}
  57. pushdown(k);int mid=(s[k].l+s[k].r)>>1;
  58. if(r<=mid) modify(k<<1,l,r,x);
  59. else if(l>mid) modify(k<<1|1,l,r,x);
  60. else modify(k<<1,l,mid,x),modify(k<<1|1,mid+1,r,x);
  61. pushup(k);
  62. }
  63. void addcnt(int k,int l,int r,int x){
  64. if(l>r) return;
  65. if(l<=s[k].l&&s[k].r<=r){
  66. if(!s[k].mn) s[k].cnt_lz+=x,s[k].sum+=s[k].num;
  67. return;
  68. } pushdown(k);int mid=(s[k].l+s[k].r)>>1;
  69. if(r<=mid) addcnt(k<<1,l,r,x);
  70. else if(l>mid) addcnt(k<<1|1,l,r,x);
  71. else addcnt(k<<1,l,mid,x),addcnt(k<<1|1,mid+1,r,x);
  72. pushup(k);
  73. }
  74. int querynum(int k,int l,int r){
  75. if(l<=s[k].l&&s[k].r<=r) return (!s[k].mn)*s[k].num;
  76. pushdown(k);int mid=(s[k].l+s[k].r)>>1;
  77. if(r<=mid) return querynum(k<<1,l,r);
  78. else if(l>mid) return querynum(k<<1|1,l,r);
  79. else return querynum(k<<1,l,mid)+querynum(k<<1|1,mid+1,r);
  80. }
  81. ll query(int k,int l,int r){
  82. if(l<=s[k].l&&s[k].r<=r) return s[k].sum;
  83. pushdown(k);int mid=(s[k].l+s[k].r)>>1;
  84. if(r<=mid) return query(k<<1,l,r);
  85. else if(l>mid) return query(k<<1|1,l,r);
  86. else return query(k<<1,l,mid)+query(k<<1|1,mid+1,r);
  87. }
  88. int mx[MAXN+5],mxtp=0,mn[MAXN+5],mntp=0;
  89. int main(){
  90. scanf("%d",&n);for(int i=1;i<=n;i++) scanf("%d",&a[i]);scanf("%d",&qu);
  91. for(int i=1;i<=qu;i++) scanf("%d%d",&q[i].l,&q[i].r),qv[q[i].r].pb(i);
  92. build(1,1,n);
  93. for(int i=1;i<=n;i++){
  94. while(mntp&&a[mn[mntp]]>a[i]) modify(1,mn[mntp-1]+1,mn[mntp],a[mn[mntp]]-a[i]),mntp--;mn[++mntp]=i;
  95. while(mxtp&&a[mx[mxtp]]<a[i]) modify(1,mx[mxtp-1]+1,mx[mxtp],a[i]-a[mx[mxtp]]),mxtp--;mx[++mxtp]=i;
  96. modify(1,1,i-1,-1);addcnt(1,1,i,1);ffe(it,qv[i]) ans[*it]=query(1,q[*it].l,q[*it].r);
  97. // for(int j=1;j<=i;j++) printf("%d %d %d\n",j,i,querynum(1,j,i));
  98. }
  99. for(int i=1;i<=qu;i++) printf("%lld\n",ans[i]);
  100. return 0;
  101. }

感觉跟 SP1557 有点像,当时还写了篇题解来着的?

Codeforces 997E - Good Subsegments(线段树维护最小值个数+历史最小值个数之和)的更多相关文章

  1. Codeforces 1136E(转化+线段树维护)

    题目传送 虽然线段树比较显然但是发现a数组并不好维护.考虑将a转化为好维护的数组b. 方法 这里我将k[1]设为0,对应着\[a[1] + k[1] <= a[2]\]不难得出\[a[i] + ...

  2. Codeforces 460C 二分结果+线段树维护

    发现最近碰到好多次二分结果的题目,上次多校也是,被我很机智的快速过了,这个思想确实非常不错.在正面求比较难处理的时候,二分结果再判断是否有效往往柳暗花明. 这个题目给定n个数字的序列,可以操作m次,每 ...

  3. Codeforces 1093G题解(线段树维护k维空间最大曼哈顿距离)

    题意是,给出n个k维空间下的点,然后q次操作,每次操作要么修改其中一个点的坐标,要么查询下标为[l,r]区间中所有点中两点的最大曼哈顿距离. 思路:参考blog:https://blog.csdn.n ...

  4. Codeforces 777E Hanoi Factory(线段树维护DP)

    题目链接 Hanoi Factory 很容易想到这是一个DAG模型,那么状态转移方程就出来了. 但是排序的时候有个小细节:b相同时看a的值. 因为按照惯例,堆塔的时候肯定是内半径大的在下面. 因为N有 ...

  5. 牛客 Rabbit的数列 (线段树维护值为x的个数+区间覆盖)

    https://ac.nowcoder.com/acm/contest/907/C 链接:https://ac.nowcoder.com/acm/contest/907/C来源:牛客网 题目描述 Ra ...

  6. 2016shenyang-1002-HDU5893-List wants to travel-树链剖分+线段树维护不同区间段个数

    肯定先无脑树链剖分,然后线段树维护一段区间不同个数,再维护一个左右端点的费用. 线段树更新,pushDown,pushUp的时候要注意考虑链接位置的费用是否相同 还有就是树链剖分操作的时候,维护上一个 ...

  7. Codeforces GYM 100114 D. Selection 线段树维护DP

    D. Selection Time Limit: 1 Sec Memory Limit: 256 MB 题目连接 http://codeforces.com/gym/100114 Descriptio ...

  8. Codeforces Round #271 (Div. 2) E题 Pillars(线段树维护DP)

    题目地址:http://codeforces.com/contest/474/problem/E 第一次遇到这样的用线段树来维护DP的题目.ASC中也遇到过,当时也非常自然的想到了线段树维护DP,可是 ...

  9. Codeforces 834D The Bakery【dp+线段树维护+lazy】

    D. The Bakery time limit per test:2.5 seconds memory limit per test:256 megabytes input:standard inp ...

  10. [Codeforces]817F. MEX Queries 离散化+线段树维护

    [Codeforces]817F. MEX Queries You are given a set of integer numbers, initially it is empty. You sho ...

随机推荐

  1. Pycharm无法打开,双击没反应

    以下方案皆为引用,仅供参考. 方案一: 1.先声明一下,这种解决方法适用于任何版本的永久破解启动不了的情况(包括:2019版本的)2.下面直接切入正题之所以我们破解之后,不能正常启动的原因有两种:① ...

  2. Java/JDK/J2SE

    Java8与JDK1.8与JDK8与J2SE8与J2SE1.8的区别是什么? Java是面向对象的编程语言,在我们开发Java应用的程序员的专业术语里,Java这个单词其实指的是Java开发工具,也就 ...

  3. [敏捷软工团队博客]Beta阶段事后分析

    设想和目标 我们的软件要解决什么问题?是否定义得很清楚?是否对典型用户和典型场景有清晰的描述? 我们的软件要解决的问题是:现在的软工课程的作业分布在博客园.GitHub上,没有一个集成多种功能的一体化 ...

  4. GT考试

    比较神仙的$dp+KMP+Matrix$综合题目,比较值得一写 $0x00$:首先我打了一个爆搜 不过对正解并无任何启发...(逗比发言请忽略) $0x01$:基础$dp$ 状态还是比较好设的, 考虑 ...

  5. Oracle 11g 新建用户

    create user XXXuser identified by XXXpassword;--创建用户XXXuser,设置初始密码XXXpassword alter user XXXuser ide ...

  6. 转:Modelsim和Vcs+Verdi使用技巧(Linux)

    Modelsim脚本自动仿真 1.创建文件 run.do,"#"为注释符号 quit -sim #退出上次仿真 .main clear #清除上次仿真所有文件以及打印信息 vlib ...

  7. TypeError: 'encoding' is an invalid keyword argument for this function 解决Python 2.7

    在python2.7中这样调用代码 open('file/name.txt','r',encoding= 'utf-8').read() 会出现 TypeError: 'encoding' is an ...

  8. cf18B Platforms(仔细谨慎题)

    题意: In one one-dimensional world there are n platforms. Platform with index k (platforms are numbere ...

  9. JavaScript正则表达式replace的一个坑

    题图来自:https://wallhaven.cc/w/md353k 经常听大家说JavaScript是魔法语言,咱却没有什么深刻体会.直到这回踩到这个坑,我终于醒悟了,JavaScript果然来自霍 ...

  10. Redis INFO CPU 信息详解

    一.INFO CPU 通过INFO CPU命令可以查看Redis进程对于CPU的使用情况,如下: 这几个字段的含义如下所示: used_cpu_sys: System CPU consumed by ...