「CF997E」 Good Subsegments

CF997E Good Subsegments

传送门

和 CF526F 差不多,只不过这道题是对多个子区间进行询问。

据说有一个叫析合树的东西可以在线做,不过有时间再说吧。

考虑离线询问,将每个询问固定至其右端点。

则我们要做的是在那道题的基础上,记录每个位置的历史贡献。

由于 \((i,i)\) 这个区间一直是符合条件的,故线段树根节点的最小值一定为 \(0\) ,我们只需要另外再维护一个标记,每次判断其是否与父节点的最小值一样即可。

贴代码

/*---Author:HenryHuang---*/
/*---Never Settle---*/
#include<bits/stdc++.h>
using namespace std;
const int maxn=1.2e5+5; 
int val[maxn];
int num[maxn<<2],tot[maxn<<2],tag[maxn<<2],tt[maxn<<2];
long long sum[maxn<<2]; 
void up(int t){
	num[t]=min(num[t<<1],num[t<<1|1]);tot[t]=0;
	if(num[t]==num[t<<1]) tot[t]+=tot[t<<1];
	if(num[t]==num[t<<1|1]) tot[t]+=tot[t<<1|1];
	sum[t]=sum[t<<1]+sum[t<<1|1];
	return ;
}
void down(int t){
	if(tag[t]){
		num[t<<1]+=tag[t],num[t<<1|1]+=tag[t];
		tag[t<<1]+=tag[t],tag[t<<1|1]+=tag[t];
		tag[t]=0;
	}
	if(tt[t]){
		if(num[t<<1]==num[t]) sum[t<<1]+=1ll*tot[t<<1]*tt[t],tt[t<<1]+=tt[t]; 
		if(num[t<<1|1]==num[t]) sum[t<<1|1]+=1ll*tot[t<<1|1]*tt[t],tt[t<<1|1]+=tt[t];
		tt[t]=0;
	}
}
void build(int l,int r,int t){
	if(l==r){
		num[t]=tot[t]=1;
		return ;
	}
	int mid=(l+r)>>1;
	build(l,mid,t<<1);
	build(mid+1,r,t<<1|1);
	up(t);return ;
}
void update(int ll,int rr,int l,int r,int nu,int t){
	if(ll<=l&&r<=rr){
		tag[t]+=nu;
		num[t]+=nu;
		return ;
	}
	int mid=(l+r)>>1;down(t);
	if(ll<=mid) update(ll,rr,l,mid,nu,t<<1);
	if(rr>mid) update(ll,rr,mid+1,r,nu,t<<1|1);
	up(t);return ;
}
long long query(int ll,int rr,int l,int r,int t){
	if(ll<=l&&r<=rr){
		return sum[t];
	}
	int mid=(l+r)>>1;down(t);long long tmp=0;
	if(ll<=mid) tmp+=query(ll,rr,l,mid,t<<1);
	if(rr>mid) tmp+=query(ll,rr,mid+1,r,t<<1|1);
	return tmp;
}
stack<pair<int,int> > mn,mx;
long long ans[maxn];
vector<pair<int,int> > opt[maxn];
int owo[maxn];
int main(){
	ios::sync_with_stdio(0);
	cin.tie(0),cout.tie(0);
	int n;cin>>n;
	for(int i=1;i<=n;++i){
		int b;cin>>b;
		val[i]=b;
	}
	int Q;cin>>Q;
	for(int i=1;i<=Q;++i){
		int l,r;cin>>l>>r;
		opt[r].emplace_back(l,i);
	}
	mx.emplace(0,2e9),mn.emplace(0,0);
	build(1,n,1);
	for(int i=1;i<=n;++i){
		int p,q;
		while((!mx.empty())&&mx.top().second<=val[i]){
			tie(p,q)=mx.top();mx.pop();
			update(mx.top().first+1,p,1,n,val[i]-q,1);
		}
		mx.emplace(i,val[i]);
		while((!mn.empty())&&mn.top().second>=val[i]){
			tie(p,q)=mn.top();mn.pop();
			update(mn.top().first+1,p,1,n,q-val[i],1);
		}
		mn.emplace(i,val[i]);
		update(1,i,1,n,-1,1);//[i,i]一定合法 
		++tt[1],sum[1]+=tot[1];
		for(auto x:opt[i]){
			tie(p,q)=x;
			ans[q]+=query(p,i,1,n,1);
		}
	}
	for(int i=1;i<=Q;++i) cout<<ans[i]<<'\n';
	return 0;
}
posted @ 2021-02-09 18:59  Henry__Huang  阅读(77)  评论(0编辑  收藏  举报