题解 O

传送门

好题!
但数据是拿脚造的并且官方题解写得像shit一样
康不懂官方题解,于是学习了dalao做法
看了一年才看懂,于是下文是在试图解释dalao题解

首先能产生贡献的点一定是单调栈中的点,但每次爆扫单调栈复杂度显然不对
于是考虑单调栈中的每个元素对所有询问的贡献,这个可以只在弹栈时考虑
于是当栈中有两个元素 \(a_i>a_j\) 时,对于任意点 \(x\),若存在一个询问满足 \(x \in[l, r] \land t\geqslant x-i\)
\(i\) 会对每个合法的 \(x\) 产生 \(a_i-a_j\) 的额外贡献
发现并不好将 \(x\) 限制在一个区间内,于是可以前缀和做差,上面的限制变为了 \(x \leqslant r \land t\geqslant x-i\)
貌似是二维偏序的一个常见处理方法:将其画到平面直角坐标系里,于是变为询问 \((r, t)\) 左下方的点权和

剩下的扔张图跑路

image

Code:
#include <bits/stdc++.h>
using namespace std;
#define INF 0x3f3f3f3f
#define N 400010
#define ll long long
// #define int long long

char buf[1<<21], *p1=buf, *p2=buf;
#define getchar() (p1==p2&&(p2=(p1=buf)+fread(buf, 1, 1<<21, stdin)), p1==p2?EOF:*p1++)
inline int read() {
	int ans=0, f=1; char c=getchar();
	while (!isdigit(c)) {if (c=='-') f=-f; c=getchar();}
	while (isdigit(c)) {ans=(ans<<3)+(ans<<1)+(c^48); c=getchar();}
	return ans*f;
}

int n, k, tot, m;
int sta[N], tem[N], top;
ll a[N], ans[N], pre[N];
struct node{int id, r, tim, op;}q[N<<3];
inline bool operator < (node a, node b) {return a.r-a.tim>b.r-b.tim;}
struct bit{
	ll a[N];
	inline void upd(int i, ll val, int lim) {for (; i<=lim; i+=i&-i) a[i]+=val;}
	inline ll query(int i) {ll ans=0; for (; i; i-=i&-i) ans+=a[i]; return ans;}
	void clear() {memset(a, 0, sizeof(a));}
}cnt, sum;

signed main()
{
	freopen("o.in", "r", stdin);
	freopen("o.out", "w", stdout);

	n=read(); k=read(); tot=k<<1;
	for (int i=1; i<=n; ++i) pre[i]=pre[i-1]+(a[i]=read());
	for (int i=1; i<=k; ++i) {
		q[i*2].tim=q[i*2-1].tim=read();
		q[i*2-1].r=read()-1;
		q[i*2].r=read();
		q[i*2-1].op=-1; q[i*2].op=1;
		q[i*2-1].id=q[i*2].id=i;
		ans[i]=pre[q[i*2].r]-pre[q[i*2-1].r];
	}
	a[n+1]=(*max_element(a+1, a+n+1))+1;
	for (int i=1; i<=n+1; ++i) {
		while (top && a[sta[top]]<a[i]) {
			int p=sta[top--];
			if (!top) break;
			q[++tot].r=p-1;
			q[tot].tim=p-1-sta[top];
			q[tot].op=a[sta[top]]-a[p];
			q[++tot].r=i-1;
			q[tot].tim=i-1-sta[top];
			q[tot].op=a[p]-a[sta[top]];
		}
		sta[++top]=i;
	}
	sort(q+1, q+tot+1);

	for (int i=1; i<=tot; ++i) tem[i]=q[i].r;
	sort(tem+1, tem+tot+1);
	m=unique(tem+1, tem+tot+1)-tem-1;
	for (int i=1,rk; i<=tot; ++i) {
		rk=lower_bound(tem+1, tem+m+1, q[i].r)-tem;
		if (!q[i].id) {
			cnt.upd(rk, q[i].op, m);
			sum.upd(rk, 1ll*q[i].r*q[i].op, m);
		}
		else ans[q[i].id]+=1ll*(1ll*q[i].r*cnt.query(rk)-sum.query(rk))*q[i].op;
	}

	for (int i=1; i<=tot; ++i) tem[i]=q[i].tim;
	sort(tem+1, tem+tot+1);
	m=unique(tem+1, tem+tot+1)-tem-1;
	cnt.clear(); sum.clear();
	for (int i=tot,rk; i; --i) {
		rk=lower_bound(tem+1, tem+m+1, q[i].tim)-tem;
		if (!q[i].id) {
			cnt.upd(rk, q[i].op, m);
			sum.upd(rk, 1ll*q[i].tim*q[i].op, m);
		}
		else ans[q[i].id]+=1ll*(1ll*q[i].tim*cnt.query(rk)-sum.query(rk))*q[i].op;
	}

	for (int i=1; i<=k; ++i) printf("%lld\n", ans[i]);

	return 0;
}
posted @ 2021-11-14 07:26  Administrator-09  阅读(1)  评论(0编辑  收藏  举报