题解:
分治的一般套路,递归处理左右区间,然后算出过 mid m i d 的答案,然后对于怎么算,一般都是分类讨论一下,对于这道题目,枚举左端点 i i <script type="math/tex" id="MathJax-Element-54">i</script>,然后根据最大最小值的位置进行分类讨论和预处理,推一大堆式子,具体怎么推可以看CQzhangyu的博客。
代码:
#include<bits/stdc++.h>
using namespace std;
#define LL long long
#define pa pair<int,int>
const int Maxn=500010;
const LL mod=1e9,inf=1e8+10;
LL read()
{
LL x=0,f=1;char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
while(ch>='0'&&ch<='9')x=(x<<3)+(x<<1)+(ch^48),ch=getchar();
return x*f;
}
int n;LL v[Maxn],ans=0;
LL t1[Maxn],t2[Maxn],t3[Maxn],t4[Maxn],t5[Maxn],t6[Maxn];
LL Sum(LL l,LL r){return ((l+r)*(r-l+1)/2LL)%mod;}
void solve(int l,int r)
{
if(l==r){ans=(ans+v[l]*v[l])%mod;return;}
int mid=l+r>>1;
solve(l,mid),solve(mid+1,r);
t1[mid]=t2[mid]=t3[mid]=t4[mid]=t5[mid]=t6[mid]=0;
LL mn=inf,mx=-inf;
for(LL i=mid+1;i<=r;i++)
{
mn=min(mn,v[i]);mx=max(mx,v[i]);
t1[i]=(t1[i-1]+mn*i%mod)%mod;t2[i]=(t2[i-1]+mn)%mod;
t3[i]=(t3[i-1]+mx*i%mod)%mod;t4[i]=(t4[i-1]+mx)%mod;
t5[i]=(t5[i-1]+mn*mx%mod*i%mod)%mod;
t6[i]=(t6[i-1]+mn*mx%mod)%mod;
}
mn=inf,mx=-inf;LL a=mid,b=mid;
LL tmp;
for(LL i=mid;i>=l;i--)
{
tmp=ans;
mn=min(mn,v[i]);mx=max(mx,v[i]);
while(a<r&&v[a+1]>=mn)a++;while(b<r&&v[b+1]<=mx)b++;
if(a<b)
{
if(a>=mid+1)ans=(ans+mn*mx%mod*Sum(mid-i+2,a-i+1)%mod)%mod;
ans=(ans+mx*((t1[b]-t1[a]+mod)%mod-(i-1)%mod*((t2[b]-t2[a]+mod)%mod)%mod+mod)%mod)%mod;
ans=(ans+((t5[r]-t5[b]+mod)%mod-(i-1)%mod*((t6[r]-t6[b]+mod)%mod)%mod+mod)%mod)%mod;
}
else
{
if(b>=mid+1)ans=(ans+mn*mx%mod*Sum(mid-i+2,b-i+1)%mod)%mod;
if(a!=b)ans=(ans+mn*((t3[a]-t3[b]+mod)%mod-(i-1)%mod*((t4[a]-t4[b]+mod)%mod)%mod+mod)%mod)%mod;
ans=(ans+((t5[r]-t5[a]+mod)%mod-(i-1)%mod*((t6[r]-t6[a]+mod)%mod)%mod+mod)%mod)%mod;
}
}
}
int main()
{
n=read();
for(int i=1;i<=n;i++)v[i]=read();
solve(1,n);
printf("%lld",ans);
}