分析:

  首先考虑如何计算整个数组有多少个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. static 的三个作用

    1).用于声明函数体内的变量为静态局部变量,存储在静态数据存储区,在函数被调用过程中维持其值保持不变 2).在文件内(函数体外)被声明为静态的变量,可以被文件内的所有函数访问,但不能被其他文件的函数访 ...

  2. Counting Cliques HDU - 5952 单向边dfs

    题目:题目链接 思路:这道题vj上Time limit:4000 ms,HDU上Time Limit: 8000/4000 MS (Java/Others),且不考虑oj测评机比现场赛慢很多,但10月 ...

  3. Git for Windows 工具的使用(二)

    Git分支  当一个人开发功能A而另一个人开发功能B,之后代码进行整合的时候,使代码既有功能A也有功能B.在Git中,Git给了我们分支的概念. 分支可以使用我们快速的开发协作,并且快速的合并. 分支 ...

  4. selenium2等待元素加载

    1.硬性等待 Thread.sleep(8000); 所谓的硬性等待就是,执行完相应操作就等待我设置的8s.无论网速快与慢,网速快的话,也许5s就打开网页了,可是程序必须接着等待剩下的3秒. 网速慢的 ...

  5. POJ2594拐点弯的二分

    开始读题没理解题意,以为就是覆盖,可是怎么交都不对... 我就气愤了,结果去百度了一下发现奶奶的这题的机器人是可以隔点瞭望的,例如1->2->3.2->4.5->2  这个图 ...

  6. js实现获取当前时间是本月第几周的方法

    这篇文章主要介绍了js实现获取当前时间是本月第几周的方法,涉及javascript针对日期及时间的相关操作技巧,非常简单实用,需要的朋友可以参考下. 本文实例讲述了js实现获取当前时间是本月第几周的方 ...

  7. SAS描述统计量

    MEANS过程 MEAN过程默认输出的统计量有:观测总数.均值.标准差.最大值和最小值.如果要计算其他统计量或其中的某一些统计量,则可在PROC语句中指定统计量的关键字. BY语句规定了分组变量,要求 ...

  8. IOS开发之----全局变量extern的使用

    extern,作用在IOS中,为了使用全局变量.比写在appDelegate和定义单例方便一些: 举例: 1.MyExternClass.h添加这个类,并在.m文件添加 代码 #import &quo ...

  9. ogre3D程序实例解析1-平移旋转与缩放

    接着上篇写 http://www.cnblogs.com/songliquan/p/3294902.html 旋转 这里有必要看一下关于旋转的源代码:    virtual void pitch(co ...

  10. SQL 与或运算

    如果一个字段需要同时包含多个信息点, 最佳的方法是进行位运算,如:1,2,4,8,16 根据与运算进行判断,如一个字段为7,判断2是否存在, 7&2 = 2为ture时,表示存在,反之亦然, ...