分析:

  首先考虑如何计算整个数组有多少个good区间

  容易发现一个区间是good区间当且仅当max-min-len=-1,且任意区间max-min-len>=-1

  我们可以枚举右端点,然后维护前面每个位置到当前右端点的max-min-len值,容易发现我们只需要维护区间最小值和最小值的个数就行了,于是用线段树即可

  于是我们可以得到以某个点为右端点的时候合法区间总数,那么我们把每次的结果加起来,就得到了整个数组有多少个good区间

  每次右端点移动怎么更新呢?显然我们只需要用一个max单调栈,一个min单调栈来帮助寻找修改区间,容易知道修改区间的个数是O(n)级别的,所以整个修改是O(nlogn)的

  好,现在我们回到原来的问题,如何求[l,r]内有多少个good区间

  在这个问题中,我们实际上要额外知道“每个区间的历史答案和”,这是什么意思呢,比如说在i=7的时候,[4,7]里的答案存的是有多少个合法的位置是和7匹配的

  但i=6的时候,[4,7]里的答案存的是有多少个合法的位置是和6匹配的

  我们自然而然就考虑到把每个右端点时刻,一个区间的产生的答案值加起来就行了,但这个时间复杂度是巨大的

  这里我们仍然可以用延迟标记来解决,比如右端点i枚举完了,我们可以给[1,i]上个tag,表示这整个区间的历史答案需要加上现在时刻的答案

  时间复杂度O(nlogn)

 #include<bits/stdc++.h>
using namespace std;
#define mp make_pair
const int maxn=;
struct wjmzbmr
{
int mi,num,tag;
int time;
long long ans;
}tree[maxn*+];
vector<pair<int,int> > q[maxn+];
long long ans[maxn+];
int a[maxn+],s[maxn+],s1[maxn+];
int len,len1;
int n,m;
void addtag(int k,int x)
{
tree[k].tag+=x;
tree[k].mi+=x;
}
void addtime(int k,int x)
{
tree[k].time+=x;
tree[k].ans+=1LL*x*tree[k].num;
}
void pushdown(int k)
{
if(tree[k].tag)
{
addtag(k*,tree[k].tag);
addtag(k*+,tree[k].tag);
tree[k].tag=;
}
if(tree[k].time)
{
if(tree[k].mi==tree[k*].mi) addtime(k*,tree[k].time);
if(tree[k].mi==tree[k*+].mi) addtime(k*+,tree[k].time);
tree[k].time=;
}
}
void update(int k)
{
tree[k].mi=min(tree[k*].mi,tree[k*+].mi);
tree[k].ans=tree[k*].ans+tree[k*+].ans;
tree[k].num=;
if(tree[k].mi==tree[k*].mi) tree[k].num+=tree[k*].num;
if(tree[k].mi==tree[k*+].mi) tree[k].num+=tree[k*+].num;
}
void build(int k,int l,int r)
{
if(l>r) return;
if(l==r)
{
tree[k].num=;
tree[k].mi=-;
return;
}
int mid=(l+r)>>;
build(k*,l,mid);
build(k*+,mid+,r);
update(k);
}
void modify(int k,int l,int r,int ql,int qr,int x)
{
if(r<ql||l>qr||l>r) return;
if(l>=ql&&r<=qr)
{
addtag(k,x);
return;
}
if(l==r) return;
pushdown(k);
int mid=(l+r)>>;
modify(k*,l,mid,ql,qr,x);
modify(k*+,mid+,r,ql,qr,x);
update(k);
}
void modify1(int k,int l,int r,int ql,int qr,int x)
{
if(r<ql||l>qr||l>r) return;
if(l>=ql&&r<=qr)
{
if(tree[k].mi==-)
addtime(k,x);
return;
}
if(l==r) return;
pushdown(k);
int mid=(l+r)>>;
modify1(k*,l,mid,ql,qr,x);
modify1(k*+,mid+,r,ql,qr,x);
update(k);
}
long long query(int k,int l,int r,int ql,int qr)
{
if(r<ql||l>qr||l>r) return ;
if(l>=ql&&r<=qr) return tree[k].ans;
if(l==r) return ;
pushdown(k);
int mid=(l+r)>>;
long long ans=query(k*,l,mid,ql,qr)+query(k*+,mid+,r,ql,qr);
update(k);
return ans;
}
int main()
{
scanf("%d",&n);
for(int i=;i<=n;++i) scanf("%d",&a[i]);
scanf("%d",&m);
for(int i=;i<=m;++i)
{
int l,r;
scanf("%d%d",&l,&r);
q[r].push_back(mp(l,i));
}
build(,,n);
for(int i=;i<=n;++i)
{
while(len&&a[s[len]]<a[i]) modify(,,n,s[len-]+,s[len],a[i]-a[s[len]]),--len;
s[++len]=i;
//for(int j=1;j<=len;++j) printf("%d ",a[s[j]]);printf("\n");
while(len1&&a[s1[len1]]>a[i]) modify(,,n,s1[len1-]+,s1[len1],a[s1[len1]]-a[i]),--len1;
s1[++len1]=i;
//for(int j=1;j<=len1;++j) printf("%d ",a[s1[j]]);printf("\n");
modify1(,,n,,i,);
for(auto x:q[i]) ans[x.second]=query(,,n,x.first,i);
//printf("%lld\n",query(1,1,n,1,i));
//if(i==4) printf("%d\n",tree[2].ans);
modify(,,n,,i,-); }
for(int i=;i<=m;++i) printf("%lld\n",ans[i]);
return ;
}

codeforces 997E(线段树)的更多相关文章

  1. Bash and a Tough Math Puzzle CodeForces 914D 线段树+gcd数论

    Bash and a Tough Math Puzzle CodeForces 914D 线段树+gcd数论 题意 给你一段数,然后小明去猜某一区间内的gcd,这里不一定是准确值,如果在这个区间内改变 ...

  2. Codeforces Round #424 (Div. 2, rated, based on VK Cup Finals) Problem E (Codeforces 831E) - 线段树 - 树状数组

    Vasily has a deck of cards consisting of n cards. There is an integer on each of the cards, this int ...

  3. Codeforces 938G 线段树分治 线性基 可撤销并查集

    Codeforces 938G Shortest Path Queries 一张连通图,三种操作 1.给x和y之间加上边权为d的边,保证不会产生重边 2.删除x和y之间的边,保证此边之前存在 3.询问 ...

  4. codeforces 1136E 线段树

    codeforces 1136E: 题意:给你一个长度为n的序列a和长度为n-1的序列k,序列a在任何时候都满足如下性质,a[i+1]>=ai+ki,如果更新后a[i+1]<ai+ki了, ...

  5. Z - New Year Tree CodeForces - 620E 线段树 区间种类 bitset

    Z - New Year Tree CodeForces - 620E 这个题目还没有写,先想想思路,我觉得这个题目应该可以用bitset, 首先这个肯定是用dfs序把这个树转化成线段树,也就是二叉树 ...

  6. D - The Bakery CodeForces - 834D 线段树优化dp···

    D - The Bakery CodeForces - 834D 这个题目好难啊,我理解了好久,都没有怎么理解好, 这种线段树优化dp,感觉还是很难的. 直接说思路吧,说不清楚就看代码吧. 这个题目转 ...

  7. B - Legacy CodeForces - 787D 线段树优化建图+dij最短路 基本套路

    B - Legacy CodeForces - 787D 这个题目开始看过去还是很简单的,就是一个最短路,但是这个最短路的建图没有那么简单,因为直接的普通建图边太多了,肯定会超时的,所以要用线段树来优 ...

  8. CodeForces 343D 线段树维护dfs序

    给定一棵树,初始时树为空 操作1,往某个结点注水,那么该结点的子树都注满了水 操作2,将某个结点的水放空,那么该结点的父亲的水也就放空了 操作3,询问某个点是否有水 我们将树进行dfs, 生成in[u ...

  9. Linear Kingdom Races CodeForces - 115E (线段树优化dp)

    大意: n条赛道, 初始全坏, 修复第$i$条花费$a_i$, m场比赛, 第$i$场比赛需要占用$[l_i,r_i]$的所有赛道, 收益为$w_i$, 求一个比赛方案使得收益最大. 设$dp[i]$ ...

随机推荐

  1. 初学Python01

    1.文本编辑器区别于交互模式的Python,它可以保存Python代码文件,再次打开还是存在.文件保存时要注意是.py的模式. 2.Windows系统下,应使用命令行模式打开.py 首先进入文件所在磁 ...

  2. set 方法总结整理

    #!/usr/bin/env python __author__ = "lrtao2010" #Python 3.7.0 集合常用方法 #集合是无序的,元素不能重复,元素只能是数字 ...

  3. hdu-1338 game predictions(贪心题)

    Suppose there are M people, including you, playing a special card game. At the beginning, each playe ...

  4. PTA 7-1 银行业务队列简单模拟

    用链表实现队列操作,代码如下: #include <iostream> #include <cstdio> #include <algorithm> #includ ...

  5. bash数组操作-定义/初始化/赋值…

    数组:     连续的多个独立内存空间,每个内存空间相当于一个变量     数组元素:数组名+索引         索引:从0开始编号             声明数组:         declar ...

  6. HDU 4990 Reading comprehension 矩阵快速幂

    题意: 给出一个序列, \(f_n=\left\{\begin{matrix} 2f_{n-1}+1, n \, mod \, 2=1\\ 2f_{n-1}, n \, mod \, 2=0 \end ...

  7. jade和ejs两者的特点

    jade特点 1超强的可读性 2灵活易用的缩进 3块扩展 4代码默认进过编码处理,以增强安全性 5编译及运行时的上下文错误报告 6命令行编译支持 7html5模式(使用 !!!5文档类型) 8可选的内 ...

  8. 什么是WSDL

    WSDL定义 WSDL(Web Service Description Language) 指网络服务描述语言:是一种用来描述Web服务和说明Web服务通信的XML.WSDL用于描述WebServic ...

  9. oracle中的dual表

    dual表是和Oracle数据字典一起创建的.它实际上只包含dummy这一个column,并且只有一条记录,这条记录的值是X. X dual表的owner是SYS,但所有用户都可以访问它.Althou ...

  10. js只能输入汉字

    var reg = new RegExp("[\\u4E00-\\u9FFF]+","g"); if(reg.test(val)){            al ...