定义:
求:
组询问。
。
在线算法,瓶颈在建出 ST 表,时间复杂度 ,吊打所有奇奇怪怪数据结构做法。
首先有:
那么只需要会求 就行了,记 并且由于 ,所以只要会求 就行了。
考虑怎么求解 ,考虑 中最左边的最大值的位置 ,它的地位是无法撼动的,所有包含 的区间最大值都是 ,所以它的贡献为 。
除去包含 的区间后,只剩下 和 的区间了。
考虑求 的贡献,设 为 的 的贡献,设 ,那么有转移 , 的贡献显然即为 。
观察到由于 是 中的最大值,所以把 ,那么预处理出 和它的前缀和即可。
的贡献也差不多,倒着求一遍 即可。
用单调栈求 和前缀和的时间复杂度是 的,预处理 ST 表的时间复杂度是 的,两个东西查询都是 的,所以时间复杂度为 。
代码如下:
#include <iostream>
#include <cstdio>
using namespace std;
#define fio(name) freopen(name".in","r",stdin),freopen(name".out","w",stdout)
const int S=100005,p=1000000000;
int n,a[S];
int top1,top2,sta1[S],sta2[S];
int pmn[S],pmx[S],smn[S],smx[S];
long long fmn[S],fmx[S],gmn[S],gmx[S];
long long sfmn[S],sfmx[S],sgmn[S],sgmx[S];
int mylog[S],mn[S][25],mx[S][25];
inline int quemn(int l,int r)
{
int k=mylog[r-l+1];
return a[mn[l][k]]<a[mn[r-(1<<k)+1][k]]?mn[l][k]:mn[r-(1<<k)+1][k];
}
inline int quemx(int l,int r)
{
int k=mylog[r-l+1];
return a[mx[l][k]]>a[mx[r-(1<<k)+1][k]]?mx[l][k]:mx[r-(1<<k)+1][k];
}
inline void slove(int l,int r,long long &mns,long long &mxs,int p)
{
int mnp=quemn(l,r);
mns+=1ll*p*a[mnp]*(mnp-l+1)*(r-mnp+1);
mns+=1ll*p*((sgmn[mnp-1]-sgmn[l-1]-gmn[mnp]*(mnp-l))+(sfmn[r]-sfmn[mnp]-fmn[mnp]*(r-mnp)));
int mxp=quemx(l,r);
mxs+=1ll*p*a[mxp]*(mxp-l+1)*(r-mxp+1);
mxs+=1ll*p*((sgmx[mxp-1]-sgmx[l-1]-gmx[mxp]*(mxp-l))+(sfmx[r]-sfmx[mxp]-fmx[mxp]*(r-mxp)));
}
int main()
{
fio("c");
n=100000;
for(int i=1,pw1=1023,pw2=1025;i<=n;i++)
{
a[i]=pw1^pw2;
pw1=1ll*pw1*1023%p,pw2=1ll*pw2*1025%p;
}
for(int i=1;i<=n;i++)
{
while(top1>0&&a[sta1[top1]]>a[i]) top1--;
while(top2>0&&a[sta2[top2]]<a[i]) top2--;
pmn[i]=sta1[top1],pmx[i]=sta2[top2];
sta1[++top1]=sta2[++top2]=i;
}
sta1[top1=0]=sta2[top2=0]=n+1;
for(int i=n;i>=1;i--)
{
while(top1>0&&a[sta1[top1]]>a[i]) top1--;
while(top2>0&&a[sta2[top2]]<a[i]) top2--;
smn[i]=sta1[top1],smx[i]=sta2[top2];
sta1[++top1]=sta2[++top2]=i;
}
for(int i=1;i<=n;i++) fmn[i]=fmn[pmn[i]]+1ll*a[i]*(i-pmn[i]),fmx[i]=fmx[pmx[i]]+1ll*a[i]*(i-pmx[i]);
for(int i=n;i>=1;i--) gmn[i]=gmn[smn[i]]+1ll*a[i]*(smn[i]-i),gmx[i]=gmx[smx[i]]+1ll*a[i]*(smx[i]-i);
for(int i=1;i<=n;i++) sfmn[i]=sfmn[i-1]+fmn[i],sfmx[i]=sfmx[i-1]+fmx[i];
for(int i=1;i<=n;i++) sgmn[i]=sgmn[i-1]+gmn[i],sgmx[i]=sgmx[i-1]+gmx[i];
mylog[0]=-1;
for(int i=1;i<=n;i++) mylog[i]=mylog[i>>1]+1,mn[i][0]=mx[i][0]=i;
for(int j=1;j<=mylog[n];j++)
{
for(int i=1;i<=n-(1<<j)+1;i++)
{
mn[i][j]=a[mn[i][j-1]]<a[mn[i+(1<<j-1)][j-1]]?mn[i][j-1]:mn[i+(1<<j-1)][j-1];
mx[i][j]=a[mx[i][j-1]]>a[mx[i+(1<<j-1)][j-1]]?mx[i][j-1]:mx[i+(1<<j-1)][j-1];
}
}
int q;
scanf("%d",&q);
while(q--)
{
int l1,r1,l2,r2;
scanf("%d%d%d%d",&l1,&r1,&l2,&r2);
if(l1>r2)
{
puts("0");
continue;
}
long long mns=0,mxs=0;
slove(l1,r2,mns,mxs,1);
if(l1<l2) slove(l1,l2-1,mns,mxs,-1);
if(r1<r2) slove(r1+1,r2,mns,mxs,-1);
if(r1<l2-1) slove(r1+1,l2-1,mns,mxs,1);
printf("%lld\n",mxs-mns);
}
return 0;
}