NOIP T4 怎么把一个暴力改改直接变正解
IvanZhang2009 · · 题解
首先需要会一个分治的
简单讲就是一次询问给定了 solve(x,y) 解决
然后考虑一个很深刻的事情:如果
我们考虑把询问的限制分成
时间复杂度
分治可以是线性的,很深刻吧!
#include<bits/stdc++.h>
using namespace std;
#define int long long
#define pii pair<int,int>
#define all(v) v.begin(),v.end()
#define pb push_back
#define REP(i,b,e) for(int i=(b);i<(int)(e);++i)
int n,q;
int a[200005],b[200005],c[200005];
int L,R;
int Q[200005];
void solve(int l,int r){
if(r-l+1<L)return;
if(l==r){
c[l]=max(c[l],a[l+1]-a[l]);
return;
}
int m=(l+r)>>1;
solve(l,m);solve(m+1,r);
int x=m+1,f1=0,f2=-1;
int mx=-1e18;
REP(i,max(l,m+1-R+1),m+1){
int ll=max(m+1,i+L-1),rr=min(r,i+R-1);
if(ll>rr){
c[i]=max(c[i],mx);
continue;
}
while(x<=rr){
while(f1<=f2&&a[Q[f2]+1]<a[x+1])--f2;
Q[++f2]=x;
++x;
}
while(f1<=f2&&Q[f1]<ll)++f1;
mx=max(mx,a[Q[f1]+1]-a[i]);
c[i]=max(c[i],mx);
}
x=m;f1=0,f2=-1;mx=-1e18;
for(int i=min(r,m+R-1);i>m;--i){
int ll=max(l,i-R+1),rr=min(m,i-L+1);
if(ll>rr){
c[i]=max(c[i],mx);
continue;
}
while(x>=ll){
while(f1<=f2&&a[Q[f2]]>a[x])--f2;
Q[++f2]=x;
--x;
}
while(f1<=f2&&Q[f1]>rr)++f1;
mx=max(mx,a[i+1]-a[Q[f1]]);
c[i]=max(c[i],mx);
}
}
int pc[50004][18][18];
void Main(){
cin>>n;
REP(i,0,n)cin>>a[i+1],a[i+1]+=a[i];
cin>>q;
int m=1;
for(int j=1;(1<<j)<=n;++j){
++m;
REP(i,0,n)c[i]=-1e18;
int ll=(1<<j),rr=(1<<(j+1))-1;rr=min(rr,n);
L=ll;R=rr;
solve(0,n-1);
REP(i,0,n)pc[i][j][j]=c[i];
}
REP(i,0,n){
REP(j,1,m){
REP(l,j+1,m){
pc[i][j][l]=max(pc[i][j][l-1],pc[i][l][l]);
}
}
}
#define ull unsigned long long
REP(i,0,q){
cin>>L>>R;
REP(j,0,n)c[j]=L==1? a[j+1]-a[j]:-1e18;
int Ll=m,Rr=-1;
REP(j,1,m){
int ll=(1<<j),rr=(1<<(j+1))-1;rr=min(rr,n);
if(L<=ll&&rr<=R){
Ll=min(Ll,j);Rr=max(Rr,j);
}else if(ll<=R||rr>=L){
int sl=L,sr=R;
L=max(L,ll);R=min(R,rr);
solve(0,n-1);
L=sl;R=sr;
}
}
if(Ll<=Rr){
REP(j,0,n)c[j]=max(c[j],pc[j][Ll][Rr]);
}
ull ans=0;
REP(j,0,n)ans^=(ull)(c[j])*(j+1);
cout<<ans<<"\n";
}
}
signed main(){
cin.tie(0);ios::sync_with_stdio(0);
int tc=1;
while(tc--)Main();
return 0;
}