人类在哪里

· · 题解

很简单的做法,可惜场上没时间搞 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 的最大值)即可把所有 ij 的贡献算上。

类似于 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'; } } ```