【BZOJ2138】stone
题面
http://darkbzoj.tk/problem/2138
题解
用类前缀和维护在给定的区间内的所有区间的价值之和,再用线段树维护区间最值。
把求全局最值转换成求当前区间左右最值那一步非常妙,是为了求出这块区域最多能被拿走多少块石子。
#include<stack> #include<queue> #include<vector> #include<cstdio> #include<cstring> #include<iostream> #define N 45000 #define ri register int using namespace std; int a[N],k[N],sum[N]; int n,m; inline int read() { int ret=0,f=0; char ch=getchar(); while (ch<'0' || ch>'9') f|=(ch=='-'),ch=getchar(); while (ch>='0' && ch<='9') ret*=10,ret+=(ch-'0'),ch=getchar(); return f?-ret:ret; } int sqr(int x) { return x*x; } struct segment_tree { int t1[N<<2],t2[N<<2]; int tag1[N<<2],tag2[N<<2]; void maketree(int x,int l,int r) { if (l==r) { t1[x]=t2[x]=sum[l]; return; } int mid=(l+r)/2; maketree(x<<1,l,mid); maketree(x<<1|1,mid+1,r); t1[x]=max(t1[x<<1],t1[x<<1|1]); t2[x]=min(t2[x<<1],t2[x<<1|1]); } void pushdown1(int x) { int k=tag1[x]; tag1[x]=0; t1[x<<1]+=k; tag1[x<<1]+=k; t1[x<<1|1]+=k; tag1[x<<1|1]+=k; } void pushdown2(int x) { int k=tag2[x]; tag2[x]=0; t2[x<<1]+=k; tag2[x<<1]+=k; t2[x<<1|1]+=k; tag2[x<<1|1]+=k; } void modify1(int x,int lb,int rb,int l,int r,int k) { if (l<=lb && rb<=r) { t1[x]+=k; tag1[x]+=k; return; } if (l>rb || r<lb) return; pushdown1(x); int mid=(lb+rb)/2; modify1(x<<1,lb,mid,l,r,k); modify1(x<<1|1,mid+1,rb,l,r,k); t1[x]=max(t1[x<<1],t1[x<<1|1]); } void modify2(int x,int lb,int rb,int l,int r,int k) { if (l<=lb && rb<=r) { t2[x]+=k; tag2[x]+=k; return; } if (l>rb || r<lb) return; pushdown2(x); int mid=(lb+rb)/2; modify2(x<<1,lb,mid,l,r,k); modify2(x<<1|1,mid+1,rb,l,r,k); t2[x]=min(t2[x<<1],t2[x<<1|1]); } int query1(int x,int lb,int rb,int l,int r) { if (l<=lb && rb<=r) return t1[x]; if (l>rb || r<lb) return -1e9; pushdown1(x); int mid=(lb+rb)/2; return max(query1(x<<1,lb,mid,l,r),query1(x<<1|1,mid+1,rb,l,r)); } int query2(int x,int lb,int rb,int l,int r) { if (l<=lb && rb<=r) return t2[x]; if (l>rb || r<lb) return 1e9; pushdown2(x); int mid=(lb+rb)/2; return min(query2(x<<1,lb,mid,l,r),query2(x<<1|1,mid+1,rb,l,r)); } } T; int main() { n=read(); int x=read(),y=read(),z=read(),p=read(); for (ri i=1;i<=n;i++) a[i]=(sqr(i-x)+sqr(i-y)+sqr(i-z))%p; m=read(); k[1]=read(); k[2]=read(); x=read(),y=read(),z=read(),p=read(); for (ri i=3;i<=m;i++) k[i]=(x*k[i-1]+y*k[i-2]+z)%p; for (ri i=1;i<=n;i++) sum[i]=sum[i-1]+a[i]; T.maketree(1,1,n); for (ri i=1;i<=m;i++) { int l=read(),r=read(); k[i]=min(k[i],T.query2(1,1,n,r,n)-max(T.query1(1,1,n,1,l-1),0)); printf("%d\n",k[i]); T.modify1(1,1,n,l,n,-k[i]); T.modify2(1,1,n,r,n,-k[i]); } return 0; }