P14638 [NOIP2025] 序列询问 / query

弱化版

草是谁做过弱化版考场上没想起来。有 85 pts 啊 /ll。

不过这个是不是确实没啥启发性啊 /yun。

分块,影响块 \([l,r]\) 中位置的答案的区间有四类。

  1. \(l'\le l,r'\in[l,r]\)

  2. \(l'\in[l,r],r\le r'\)

  3. \(l'<l,r'<r\)

  4. \(l\le l'\le r'\le r\)

假设区间长度为 \([L,R]\),以 \(L\) 为块长就能去掉第四种情况。

前两种枚举块内位置作为左/右端点,则另一端点的位置为一段区间,和弱化版中分治的处理类似,用 st 表维护前缀和 \(\min,\max\) 即可。这部分每块是 \(O(L)\) 的。

而第三种枚举右端点,左端点也为一段区间,右端点个数为 \(O(R-L)\)

假设区间长度为 \([L,R]\)。前两种复杂度为 \(O(n)\),第三种为 \(O(\frac{n}{L}R)\)

假设 \(\frac{R}{L}\) 为小常数时可以看作单次 \(O(n)\) 求解。

考虑对区间长度一维套一个倍增优化,预处理 \([2^i,2^{i+1})\) 的答案,最后合并整块两边散块可以 \(O(n)\) 求解。卡卡卡卡卡卡卡卡卡卡卡常就过了。

#include<bits/stdc++.h>
using namespace std;
#define cfast ios::sync_with_stdio(false);cin.tie(0),cout.tie(0)
#define ll long long
#define ull unsigned long long
inline void max_(ll &x,ll y){if(y>x)x=y;}
inline void min_(ll &x,ll y){if(y<x)x=y;}
#define max(x,y) ((x)>(y)?(x):(y))
#define min(x,y) ((x)<(y)?(x):(y))
const int N=5e4+5,M=16;
const ll inf=-1e12;
int n,a[N],lg[N];ll s[N],mx[N][M],mn[N][M],ans[N],w[N],res[N][M][M],f[N];
inline ll gtmx(int l,int r){int p=lg[r-l+1];return max(mx[l][p],mx[r-(1<<p)+1][p]);}
inline ll gtmn(int l,int r){int p=lg[r-l+1];return min(mn[l][p],mn[r-(1<<p)+1][p]);}
inline void solve(int L,int R){
	for(int l=1,r=L;l<=n;l+=L,r=min(l+L-1,n)){
		for(int j=l;j<=r;j++)
			w[j]=(j-L>=0?s[j]-gtmn(max(j-R,0),j-L):inf);
		for(int j=r-1;j>=l;j--)max_(w[j],w[j+1]);
		for(int j=l;j<=r;j++)ans[j]=w[j];
		for(int j=l;j<=r;j++)
			w[j]=(j+L-1<=n?gtmx(j+L-1,min(j+R-1,n))-s[j-1]:inf);
		for(int j=l+1;j<=r;j++)max_(w[j],w[j-1]);
		for(int j=l;j<=r;j++)max_(ans[j],w[j]);
		ll x=inf;
		for(int j=r+1;j<=n;j++){
			if(j-R+1>=l)break;
			max_(x,s[j]-gtmn(max(j-R,0),l-1));
		}
		for(int j=l;j<=r;j++)max_(ans[j],x);
	}
}
inline void UesugiErii(){
	cin>>n;
	for(int i=2;i<=n;i++)lg[i]=lg[i>>1]+1;
	for(int i=1;i<=n;i++)
		cin>>a[i],s[i]=s[i-1]+a[i],mx[i][0]=mn[i][0]=s[i];
	for(int i=1;i<=lg[n];i++)
		for(int j=0;j+(1<<i)-1<=n;j++){
			mx[j][i]=max(mx[j][i-1],mx[j+(1<<i-1)][i-1]),
			mn[j][i]=min(mn[j][i-1],mn[j+(1<<i-1)][i-1]);
		}
	for(int i=0;i<lg[n];i++){
		solve(1<<i,(1<<i+1)-1);
		for(int j=0;j<=n;j++)res[j][i][i]=ans[j];
	}
	for(int i=1;i<=n;i++)
		for(int j=1;j<lg[n];j++)
			for(int k=j+1;k<lg[n];k++)
				res[i][j][k]=max(res[i][k][k],res[i][j][k-1]);
	int q;cin>>q;
	while(q--){
		int L,R;ull t=0;cin>>L>>R;int l=lg[L],r=lg[R];
		if(R<(L<<1)){
			solve(L,R);
			for(int i=1;i<=n;i++)t^=(ull)(i*ans[i]);
			cout<<t<<'\n';
			continue;
		}
		if(l+1<=r-1)
			for(int i=1;i<=n;i++)f[i]=res[i][l+1][r-1];
		else for(int i=1;i<=n;i++)f[i]=inf;
		if(L!=(1<<l)){
			solve(L,(1<<l+1)-1);
			for(int i=1;i<=n;i++)max_(f[i],ans[i]);
		}else for(int i=1;i<=n;i++)max_(f[i],res[i][l][l]);
		if(R!=(1<<r+1)-1){
			solve(1<<r,R);
			for(int i=1;i<=n;i++)max_(f[i],ans[i]);
		}else for(int i=1;i<=n;i++)max_(f[i],res[i][r][r]);
		for(int i=1;i<=n;i++)t^=(ull)(i*f[i]);
		cout<<t<<'\n';
	}
}
signed main(){
	//IO();
	cfast;
	int _=1;//cin>>_;
	for(;_;_--)UesugiErii();
	return 0;
}
posted @ 2025-12-01 20:44  Uesugi1  阅读(1)  评论(0)    收藏  举报