题解:P4513 小白逛公园
补一个分块做法。
题意简化一下就是单点修改和找区间最大子段和。由于是分块,无法像线段树一样合并,并且值会有负数,所以使用动规。
至于单点修改操作以及其它数组的维护不多赘述,只讲一下如何维护
这里用到了前缀和求最大子段和,即对于每一个前缀和
注意每次单点修改时要一同修改
Code
#include<bits/stdc++.h>
using namespace std;
#define int long long
int read(){
char ch=getchar();
int r=0,w=1;
while(ch<'0'||ch>'9') w=ch=='-'?-1:w,ch=getchar();
while(ch>='0'&&ch<='9') r=r*10+ch-'0',ch=getchar();
return r*w;
}
void write(long long n){
if(n<0) putchar('-'),n*=-1;
if(n>9) write(n/10);
putchar(n%10+'0');
}
const int N=5e5+1,M=sqrt(5e5+1)*2;
int n,m,cnt,maxx,k,l,r,p,s,ll,rr,lk,rk;
int xl[N],maxl[M],maxr[M],maxk[M];
int ans[M],qzh[M][M],AC[N],cc[N];
int x[M],y[M],fk[N],dp[M][2];
signed main(){
cin>>n>>m;
cnt=sqrt(n);
for(int i=1;i<=cnt;i++){
x[i]=y[i-1]+1;
y[i]=x[i]+cnt-1;
for(int j=x[i];j<=y[i];j++){
fk[j]=i;
}
}
if(y[cnt]<n){
cnt++;
x[cnt]=y[cnt-1]+1;
y[cnt]=n;
for(int i=x[cnt];i<=n;i++){
fk[i]=cnt;
}
}
for(int i=1;i<=n;i++){
cin>>xl[i];
ans[fk[i]]+=xl[i];
}
for(int i=1;i<=fk[n];i++){
for(int j=x[i];j<=y[i];j++){
qzh[i][j-x[i]+1]=qzh[i][j-x[i]]+xl[j];
}
}
for(int i=1;i<=fk[n];i++){
maxl[i]=maxr[i]=-LLONG_MAX;
cnt=0;
for(int j=x[i];j<=y[i];j++){
cnt+=xl[j];
maxl[i]=max(maxl[i],cnt);
}
cnt=0;
for(int j=y[i];j>=x[i];j--){
cnt+=xl[j];
maxr[i]=max(maxr[i],cnt);
}
AC[x[i]]=cnt=qzh[i][1];
for(int j=x[i]+1;j<=y[i];j++){
cnt=min(cnt,qzh[i][j-x[i]+1]);
AC[j]=cnt;
}
maxk[i]=qzh[i][1];
for(int j=x[i]+1;j<=y[i];j++){
maxk[i]=max(maxk[i],max(qzh[i][j-x[i]+1],qzh[i][j-x[i]+1]-AC[j-1]));
}
}
for(int i=1;i<=m;i++){
cin>>k;
if(k==1){
cin>>l>>r;
if(l>r){
swap(l,r);
}
ll=rr=-LLONG_MAX;
cnt=0;
for(int j=min(r,y[fk[l]]);j>=l;j--){
cnt+=xl[j];
ll=max(ll,cnt);
}
cc[0]=0;
for(int j=l;j<=min(r,y[fk[l]]);j++){
cc[j-l+1]=cc[j-l]+xl[j];
}
AC[l]=cnt=cc[1];
for(int j=l+1;j<=min(r,y[fk[l]]);j++){
cnt=min(cnt,cc[j-l+1]);
AC[j]=cnt;
}
lk=cc[1];
for(int j=l+1;j<=min(r,y[fk[l]]);j++){
lk=max(lk,max(cc[j-l+1],cc[j-l+1]-AC[j-1]));
}
if(fk[l]!=fk[r]){
cnt=0;
for(int j=x[fk[r]];j<=r;j++){
cnt+=xl[j];
rr=max(rr,cnt);
}
AC[x[fk[r]]]=cnt=qzh[fk[r]][1];
for(int j=x[fk[r]]+1;j<=r;j++){
cnt=min(cnt,qzh[fk[r]][j-x[fk[r]]+1]);
AC[j]=cnt;
}
rk=qzh[fk[r]][1];
for(int j=x[fk[r]]+1;j<=r;j++){
rk=max(rk,max(qzh[fk[r]][j-x[fk[r]]+1],qzh[fk[r]][j-x[fk[r]]+1]-AC[j-1]));
}
}
else{
cout<<lk<<endl;
continue;
}
cnt=max(lk,rk);
dp[fk[l]][1]=ll;
for(int j=fk[l]+1;j<fk[r];j++){
dp[j][0]=max(dp[j-1][1],max(dp[j-1][1]+maxl[j],maxk[j]));
dp[j][1]=max(maxr[j],dp[j-1][1]+ans[j]);
}
dp[fk[r]][0]=max(dp[fk[r]-1][1],dp[fk[r]-1][1]+rr);
for(int j=fk[l]+1;j<=fk[r];j++){
cnt=max(cnt,dp[j][0]);
}
cout<<cnt<<endl;
}
else{
cin>>p>>s;
ans[fk[p]]-=xl[p];
xl[p]=s;
ans[fk[p]]+=xl[p];
for(int j=x[fk[p]];j<=y[fk[p]];j++){
qzh[fk[p]][j-x[fk[p]]+1]=qzh[fk[p]][j-x[fk[p]]]+xl[j];
}
maxl[fk[p]]=maxr[fk[p]]=-LLONG_MAX;
cnt=0;
for(int j=x[fk[p]];j<=y[fk[p]];j++){
cnt+=xl[j];
maxl[fk[p]]=max(maxl[fk[p]],cnt);
}
cnt=0;
for(int j=y[fk[p]];j>=x[fk[p]];j--){
cnt+=xl[j];
maxr[fk[p]]=max(maxr[fk[p]],cnt);
}
AC[x[fk[p]]]=cnt=qzh[fk[p]][1];
for(int j=x[fk[p]]+1;j<=y[fk[p]];j++){
cnt=min(cnt,qzh[fk[p]][j-x[fk[p]]+1]);
AC[j]=cnt;
}
maxk[fk[p]]=qzh[fk[p]][1];
for(int j=x[fk[p]]+1;j<=y[fk[p]];j++){
maxk[fk[p]]=max(maxk[fk[p]],max(qzh[fk[p]][j-x[fk[p]]+1],qzh[fk[p]][j-x[fk[p]]+1]-AC[j-1]));
}
}
}
return 0;
}