分析:

  首先考虑如何计算整个数组有多少个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. POJ:3160-Father Christmas flymouse

    Father Christmas flymouse Time Limit: 1000MS Memory Limit: 131072K Description After retirement as c ...

  2. 创建dll及使用

    一.创建动态链接库文件 ** 1.打开VS2013,选择文件,新建工程  2.选择新建W32控制台应用程序,这里将工程名改为makeDLL  3.在应用程序类型中选择DLL,点击完成  4.完成以上步 ...

  3. luogu4001 [BJOI2006]狼抓兔子

    裸dinic就跑过去了,哪用得着平面图最小割=最短路-- #include <iostream> #include <cstring> #include <cstdio& ...

  4. windows基本DOS命令

    基本命令 dir : 列出当前目录下的文件以及文件夹,后面可以接其他路径 md : 创建目录(mkdir),一次创建多级目录,mkdir a\b\c rd : 删除目录,删除非空目录rd /s(删除最 ...

  5. 大咖分享 | 一文解锁首届云创大会干货——上篇(文末附演讲ppt文件免费下载)

    日,第一届网易云创大会在杭州国际博览中心举办,本次大会由杭州滨江区政府和网易主办,杭州市两创示范工作领导小组办公室协办,网易云承办,以"商业匠心.技术创新"为主题,致力于打通技术创 ...

  6. [svn学习篇]svn使用教程

    http://www.cnblogs.com/longshiyVip/p/4905901.html http://blog.csdn.net/dily3825002/article/details/6 ...

  7. javascript学习笔记 - 引用类型 Date

    三 Date new Date() 在不传递参数的情况下,新创建的对象自动获得当前日期和时间.参数接收毫秒的timestamp Date.parse() 接收表示日期的字符串,返回相应的日期毫秒数ti ...

  8. URAL 1137Bus Routes (dfs)

    Z - Bus Routes Time Limit:1000MS     Memory Limit:65536KB     64bit IO Format:%I64d & %I64u Subm ...

  9. poj1006 中国剩余定理&&中国剩余定理解析

    poj 1006 题的思路不是很难的,可以转化数学式: 现设 num 是下一个相同日子距离开始的天数 p,e,i,d 如题中所设! 那么就可以得到三个式子:( num + d ) % 23 == p: ...

  10. [BZOJ3817]Sum

    [BZOJ3817]Sum 试题描述 给定正整数N,R.求 输入 第一行一个数 T,表示有 T 组测试数据. 接下来 T 行,每行两个正整数 n,r. 输出 输出 T 行,每行一个整数表示答案. 输入 ...