分析:

  首先考虑如何计算整个数组有多少个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. python 项目中包中__init__.py文件的作用

    开发python项目时,我遇到了一个这样的现象,当我新建一个pythonpackage时,总会自动地生成一个空的__init__.py文件,因为是python新手,所以很不了解这个空文件的作用是什么, ...

  2. LeetCode(287)Find the Duplicate Number

    题目 Given an array nums containing n + 1 integers where each integer is between 1 and n (inclusive), ...

  3. Linux集群之高可用负载均衡lvs+keepalived

    LVS简介 LVS介绍 LVS是Linux Virtual Server的缩写,意即Linux虚拟服务器,是一个虚拟的服务器集群系统,属于4层负载均衡 ipvs和ipvsadm的关系 我们使用配置LV ...

  4. Linux学习-systemctl 针对 timer 的配置文件

    如何使用 systemd 内建的 time 来处理各种任务呢? systemd.timer 的优势 在 archlinux 的官网 wiki 上面有提到,为啥要使用 systemd.timer 呢? ...

  5. SPOJ375 Query on a tree(树链剖分)

    传送门 题意 给出一棵树,每条边都有权值,有两种操作: 把第p条边的权值改为x 询问x,y路径上的权值最大的边 code #include<cstdio> #include<algo ...

  6. (转)React 入门实例教程

    作者: 阮一峰 现在最热门的前端框架,毫无疑问是 React . 上周,基于 React 的 React Native 发布,结果一天之内,就获得了 5000 颗星,受瞩目程度可见一斑. React ...

  7. Python学习——第一天

    https://www.runoob.com/python/python-chinese-encoding.html 第一个python程序 [root@mini1 ~]# vi python01.p ...

  8. 运行Android程序出错:The connection to adb is down, and a severe error has occured

    调试Android程序时候,报错如下: [2013-02-21 15:41:06 - MainActivity] ------------------------------[2013-02-21 1 ...

  9. centos7 install google-chrome

    important: Google Chrome support for all 32-bit Linux distributions is deprecated from March, 2016. ...

  10. Problem 1004: 蛤玮打扫教室(区间覆盖端点记录)

    Problem 1004: 蛤玮打扫教室 Time Limits:  1000 MS   Memory Limits:  65536 KB 64-bit interger IO format:  %l ...