NORMA2

传送门

我们考虑分治,处理(solve(l,r))时算出所有过(mid)区间的贡献

考虑先枚举左侧点,同时预处理数组

(s_1=sumlimits_{i=mid+1}^{r}(i-mid)*max{a[mid+1->i]})
(s_1^{'}=sumlimits_{i=mid+1}^{r}max{a[mid+1->i]})

同时(s2,s3)分别求最大值和最大值乘最小值

枚举区间的左端点出,找到(mid)右侧第一个小于左侧最小值的点(j)和大于左侧最大值的点(k)

不失一般性的考虑(j<k)的情况

为了方便,我们让(j=j-1,k=k-1)

对于(mid+1->j)的部分,最大值和最小值在枚举左端点的时候可以处理出来

这部分贡献是等差数列求和乘最大值和最小值

[minn*maxn*frac{((mid+1-l+1)+(j-l+1))*(j-(mid+1)+1)}{2} ]

对于(j+1->k)我们的最大值仍然是(maxn),最小值发生了变化

[maxn*((s_1[k]-s_1[j])+(mid-l+1)*(s_1^{`}[k]-s_1^{`}[j])) ]

最后(k+1->r)这部分完全和左边值无关了

[((s_3[r]-s_3[k])+(mid-l+1)*(s_3^{`}[r]-s_3^{`}[k])) ]

然后分治下去就好了,注意判断(l==r)的边界

#include<bits/stdc++.h>
using namespace std;
namespace red{
#define int long long
#define ls(p) (p<<1)
#define rs(p) (p<<1|1)
#define y1 qwq 
	inline int read()
	{
		int x=0;char ch,f=1;
		for(ch=getchar();(ch<'0'||ch>'9')&&ch!='-';ch=getchar());
		if(ch=='-') f=0,ch=getchar();
		while(ch>='0'&&ch<='9'){x=(x<<1)+(x<<3)+ch-'0';ch=getchar();}
		return f?x:-x;
	}
	const int N=5e5+10,p=1e9;
	int n,ans;
	int a[N],s1[N],s2[N],s3[N],s1_[N],s2_[N],s3_[N];
	inline void sakura(int l,int r)
	{
		if(l==r){(ans+=a[l]*a[l]%p)%=p;return;}
		int mid=(l+r)>>1,minn=a[mid],maxn=a[mid],i=mid,j=mid,k=mid;
		int t1=a[mid+1],t2=a[mid+1];
		s1[mid]=s2[mid]=s3[mid]=s1_[mid]=s2_[mid]=s3_[mid]=0;
		for(int i=mid+1;i<=r;++i)
		{
			t1=min(t1,a[i]),t2=max(t2,a[i]);
			(s1[i]=s1[i-1]+t1*(i-(mid+1)+1)%p)%=p;
			(s1_[i]=s1_[i-1]+t1)%=p;
			
			(s2[i]=s2[i-1]+t2*(i-(mid+1)+1)%p)%=p;
			(s2_[i]=s2_[i-1]+t2)%=p;
			
			(s3[i]=s3[i-1]+t1*t2%p*(i-(mid+1)+1)%p)%=p;
			(s3_[i]=s3_[i-1]+t1*t2%p)%=p;
		}
		while(i>=l)
		{
			minn=min(minn,a[i]),maxn=max(maxn,a[i]);
			while(j<r&&a[j+1]>minn) ++j;
			while(k<r&&a[k+1]<maxn) ++k;
			int w1=min(j,k),w2=max(j,k);
			if(w1>mid) (ans+=minn*maxn%p*((mid+1-i+1+w1-i+1)*(w1-(mid+1)+1)/2%p)%p)%=p;
			if(j>w1) (ans+=minn*((s2[j]-s2[w1]+p)%p+(mid-i+1)*(s2_[j]-s2_[w1]+p)%p)%p)%=p;
			if(k>w1) (ans+=maxn*((s1[k]-s1[w1]+p)%p+(mid-i+1)*(s1_[k]-s1_[w1]+p)%p)%p)%=p;
			(ans+=((s3[r]-s3[w2]+p)%p+(mid-i+1)*(s3_[r]-s3_[w2]+p)%p)%p)%=p;
			--i;
		}
		sakura(l,mid);sakura(mid+1,r);
	}
	inline void main()
	{
		n=read();
		for(int i=1;i<=n;++i) a[i]=read();
		sakura(1,n);
		printf("%lld
",ans%p);
	}
}
signed main()
{
	red::main();
	return 0;
}

(sakura)最好啦

原文地址:https://www.cnblogs.com/knife-rose/p/12643797.html