【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
",k[i]);
    T.modify1(1,1,n,l,n,-k[i]); T.modify2(1,1,n,r,n,-k[i]);
  }
  return 0;
}
原文地址:https://www.cnblogs.com/shxnb666/p/11323893.html