CF1117G Recursive Queries

题意

给出长度为\(n\)的排列,假设\(m_{l,r}\)为区间\([l,r]\)中最大值对应的下标,定义函数 \(f(l,r)=(r-l+1)+f(l,m_{l,r}-1)+f(m_{l,r}+1,r)\),若\(r<l\)则返回\(0\)

\(q\)次询问\(f(l_i,r_i)\)的值。

\(1 \leq n,q \leq 10^6\)

传送门

思路

单调栈预处理出\(l[i]\)表示\(i\)左边第一个比它大的位置\(+1\)\(r[i]\)表示右边第一个比它大的位置\(-1\)

在询问\((L,R)\)中,对区间每个点考虑,当它成为\(max\)时区间长度贡献就是\(\text{min}(R,r[i])-\text{max}(L,l[i])+1\)

将两个分开计算,只讨论\(\text{max}(L,l[i])\),前面的同理。

开两个树状数组,一个记和,一个记个数。从小到大枚举右端点\(i\),加入\(i\)时,比较\(L,l[i]\)的大小:

  1. \(1 \leq L \leq l[i]\)时,\(l[i] \geq L\),区间\(+l[i]\)
  2. \(l[i] < L \leq i\)时,\(L>l[i]\),区间加等差数列\(L\),区间个数\(+n1\)即可。

询问离线,对于右端点为\(i\)的询问\((L,i)\),此部分答案为\(-sum[L]-cnt[L] \times L\)

同样枚举一遍左端点即可,最后答案加上区间长度。

#include <bits/stdc++.h>
using std::vector;
typedef long long ll;
const int N=1000005;
int n,Q,a[N],l[N],r[N],st[N],tp;
vector<int> el[N],er[N];
ll s[N],ans[N],c[N];
int lowbit(int x){
	return x&(-x);
}
void upd(ll *s,int x,int y){
	while (x<=n){
		s[x]+=y;
		x+=lowbit(x); 
	}
}
ll getsum(ll *s,int x){
	ll ret=0;
	while (x){
		ret+=s[x];
		x-=lowbit(x);
	}
	return ret;
}
void add(ll *s,int l,int r,int x){
	if (l>r) return;
	upd(s,l,x),upd(s,r+1,-x);
}
struct query{
	int l,r,id;
}q[N];
int main(){
	scanf("%d%d",&n,&Q);
	for (int i=1;i<=n;i++) scanf("%d",&a[i]);
	for (int i=1;i<=n;i++){
		while (tp && a[st[tp]]<=a[i]) tp--;
		l[i]=st[tp]+1;
		st[++tp]=i;
	}
	tp=0;
	for (int i=n;i>=1;i--){
		while (tp && a[st[tp]]<=a[i]) tp--;
		r[i]=tp?st[tp]-1:n;
		st[++tp]=i; 
	}
	for (int i=1;i<=Q;i++) scanf("%d",&q[i].l),el[q[i].l].push_back(i);
	for (int i=1;i<=Q;i++) scanf("%d",&q[i].r),er[q[i].r].push_back(i);
	for (int i=1;i<=n;i++){
		add(s,1,l[i],l[i]);
		add(c,l[i]+1,i,1);
		for (auto j:er[i]) ans[j]=-getsum(s,q[j].l)-getsum(c,q[j].l)*q[j].l;
	}
	memset(s,0,sizeof(s));
	memset(c,0,sizeof(c));
	for (int i=n;i>=1;i--){
		add(s,r[i],n,r[i]);
		add(c,i,r[i]-1,1);
		for (auto j:el[i]) ans[j]+=getsum(s,q[j].r)+getsum(c,q[j].r)*q[j].r;
	}
	for (int i=1;i<=Q;i++) printf("%lld ",ans[i]+q[i].r-q[i].l+1);
} 
posted @ 2020-07-11 20:57  flyfeather  阅读(135)  评论(0编辑  收藏  举报