人类在哪里
NATO
·
·
题解
很简单的做法,可惜场上没时间搞 O(nq) 了。
考虑特殊性质 D 的做法。
考虑枚举区间的左端点 i\in[1,n-l+1],对于每个 i 有可能的右端点 [i+l-1,\min(n,i+r-1)]。
注意到对于 j\in[i,i+l-1] 这一部分 i 为左端点的贡献必然是最优的,也就是 [i+l-1,\min(n,i+r-1)] 中前缀和最大的值减去 i-1 的前缀和。
对每个 i 求出这个最优值 val_i 后你再做一个长度为 l 的滑动窗口([j-l+1,j] 中 val 的最大值)即可把所有 i 对 j 的贡献算上。
类似于 l,你同样可以枚举 r 算这样一个贡献。
你发现对于一个 j,你必然把所有满足它作为一个区间左端点及之后不超过 l 个数或右端点及之前不超过 l 个数的区间都贡献上了。
也即是长度为 [l,2l-1] 的区间必然已经贡献过了!
上述过程均可以在预处理 ST 表后 O(n) 完成。
你发现你实现了 l 翻倍,即 O(nq) 的 D 性质。
你还可以得到一个普适性的 O(n\log n+nq\log n) 的做法(l 翻倍不超过 \log n 次)且是符合除 C 以外特殊性质的做法,期望得分 65。
考虑预处理所有 $[2^i,2^{i+1}-1]$ 的答案,然后得到任意 $[2^i,2^j-1](i<j)$ 的答案,这样你每次询问就只用跑 $[l,2^{\lfloor\log l\rfloor+1}-1],[2^{\lfloor\log r\rfloor},r]$ 的答案了,其他部分直接调用即可。
时间复杂度 $O(n\log^2n+qn)$,洛谷可能较为卡常。
代码:
```cpp
#include<bits/stdc++.h>
#define ll long long
#define un unsigned
#define INF 214748364719260817ll
using namespace std;
int n,q,lg[50005];
ll a[50005];
ll maxn[16][50005],minn[16][50005];
inline ll get_maxn(int l,int r)
{
int len=lg[r-l+1];
return max(maxn[len][l],maxn[len][r-(1<<len)+1]);
}
inline ll get_minn(int l,int r)
{
int len=lg[r-l+1];
return min(minn[len][l],minn[len][r-(1<<len)+1]);
}
ll res[50005],val[50005];
int k[50005];
ll cot;
inline void done(int l,int r,ll *res)
{
++cot;
int st=1,ed=0;
for(int i=1;i<=n;++i)
{
int nl=i+l-1,nr=min(i+r-1,n);
val[i]=(nl<=n)?(get_maxn(nl,nr)-a[i-1]):-INF;
while(st<=ed&&val[k[ed]]<=val[i])--ed;
while(st<=ed&&i-k[st]+1>l)++st;
k[++ed]=i;
res[i]=max(res[i],val[k[st]]);
}
st=1,ed=0;
for(int i=n;i;--i)
{
int nr=i-l+1,nl=max(1,i-r+1);
val[i]=(nr>0?a[i]-get_minn(nl,nr):-INF);
while(st<=ed&&val[k[ed]]<=val[i])--ed;
while(st<=ed&&k[st]-i+1>l)++st;
k[++ed]=i;
res[i]=max(res[i],val[k[st]]);
}
}
ll v[16][50005];
ll y[16][16][50005];
int main()
{
// freopen("query.in","r",stdin);
// freopen("query.out","w",stdout);
ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);
cin>>n;
lg[0]=-1;
for(ll i=1;i<=n;++i)cin>>a[i],lg[i]=lg[i>>1]+1,a[i]+=a[i-1];
memset(minn,16,sizeof(minn));
for(ll i=1;i<=n;++i)minn[0][i]=a[i-1],maxn[0][i]=a[i];
for(ll j=1;j<=15;++j)
for(ll i=1;i+(1<<j)-1<=n;++i)
minn[j][i]=min(minn[j-1][i],minn[j-1][i+(1<<(j-1))]),maxn[j][i]=max(maxn[j-1][i],maxn[j-1][i+(1<<(j-1))]);
memset(y,128,sizeof(y));
memset(v,128,sizeof(v));
for(ll i=0;(1<<(i+1))-1<=n;++i)
{
done((1<<i),(1<<(i+1))-1,v[i]);
--cot;
for(ll j=i;j>=0;--j)
{
for(ll k=1;k<=n;++k)
y[j][i][k]=max((i)?y[j][i-1][k]:-INF,v[i][k]);
}
}
cin>>q;
ll l,r;
memset(res,128,sizeof(res));
while(q--)
{
cin>>l>>r;
if((1<<lg[l])==l&&r==(1<<(lg[r]+1))-1)
{
for(int i=1;i<=n;++i)res[i]=y[lg[l]][lg[r]][i];
}
else if(2*l>r)done(l,r,res);
else
{
ll lv=lg[l];
if((1<<lv)!=l)
done(l,(1<<(lv+1))-1,res);
else
--lv;
ll rv=lg[r];
if((1<<(rv+1))-1!=r)
done((1<<rv),r,res);
else
++rv;
if(lv+1<=rv-1)
for(int i=1;i<=n;++i)res[i]=max(res[i],y[lv+1][rv-1][i]);
}
un ll ans=0;
for(int i=1;i<=n;++i)
ans^=((un ll)(i)*(un ll)res[i]),res[i]=-INF;
cout<<ans<<'\n';
}
}
```