洛谷题解P4314CPU监控--线段树

题目链接

https://www.luogu.org/problemnew/show/P4314

https://www.lydsy.com/JudgeOnline/problem.php?id=3064

分析

其实我是在看吉司机线段树课件时看到这题很感兴趣就跑过来做

显然如果数据小一点可以用分块什么的比较好搞

但是这个数据范围可能用\(log N\)的数据结构更舒服一点

怎么搞呢?请阅读国家集训队2016论文集之《区间最值操作与历史最值问题——杭州学军中学 吉如一》,对,就是我们敬爱可亲的吉司机.

看不懂?实际上就是告诉我们维护6个\(lazy\)_\(tag\):

  1. \(nmx\)表示当前区间最大值,\(add\)表示当前区间加法标记,\(set\)表示当前区间赋值标记

  2. \(pmx\)表示当前区间历史最大值,\(padd\)表示当前区间在下传此标记前时历史最大加法标记,\(pset\)表示当前区间在下传此标记前历史最大赋值标记

这样\(lazy\)_\(tag\)之间的合并就比较显然了

然后再结合论文食用,或是看代码理解一下

当然GXZlegend大佬使用吉司机的另一个方法也是可行的

http://www.cnblogs.com/GXZlegend/p/8315275.html

注意

我查错又查了一个小时

  • 注意不要把\(-inf\)写成\(inf\)

  • \(pushdown\)时思维一定要清晰,注意是哪些标记会对其他标记产生影响

代码

#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <algorithm>
#include <cctype>
#include <iostream>
#define ll long long 
#define ri register int 
using std::max;
const int inf=0x3f3f3f3f;
const int maxn=100005;
template <class T>inline void read(T &x){
  x=0;int ne=0;char c;
  while(!isdigit(c=getchar()))ne=c=='-';
  x=c-48;
  while(isdigit(c=getchar()))x=(x<<3)+(x<<1)+c-48;
  x=ne?-x:x;return ;
}
int n;
int nmx[maxn<<2],add[maxn<<2],set[maxn<<2];
int pmx[maxn<<2],padd[maxn<<2],pset[maxn<<2];
int num[maxn];
int L,R,dta;
void build(int now,int l,int r){
  set[now]=nmx[now]=pmx[now]=pset[now]=-inf;
  padd[now]=add[now]=0;
  if(l==r){
      nmx[now]=pmx[now]=num[l];
      return ;
  }
  int mid=(l+r)>>1;
  build(now<<1,l,mid);
  build(now<<1|1,mid+1,r);
  nmx[now]=pmx[now]=max(nmx[now<<1],nmx[now<<1|1]);
  return ;
}
inline void pushdown(int now){
  if(padd[now]){
      pmx[now<<1]=max(pmx[now<<1],nmx[now<<1]+padd[now]);
      if(set[now<<1]!=-inf)
          pset[now<<1]=max(pset[now<<1],set[now<<1]+padd[now]);
      else 
          padd[now<<1]=max(padd[now<<1],add[now<<1]+padd[now]);
      pmx[now<<1|1]=max(pmx[now<<1|1],nmx[now<<1|1]+padd[now]);
      if(set[now<<1|1]!=-inf)
          pset[now<<1|1]=max(pset[now<<1|1],set[now<<1|1]+padd[now]);
      else 
          padd[now<<1|1]=max(padd[now<<1|1],add[now<<1|1]+padd[now]);
      padd[now]=0;
  }
  if(pset[now]!=-inf){
      pmx[now<<1]=max(pmx[now<<1],pset[now]);
      pset[now<<1]=max(pset[now<<1],pset[now]);
      pmx[now<<1|1]=max(pmx[now<<1|1],pset[now]);
      pset[now<<1|1]=max(pset[now<<1|1],pset[now]);
      pset[now]=-inf;
  }
  if(add[now]){
      nmx[now<<1]+=add[now];
      pmx[now<<1]=max(pmx[now<<1],nmx[now<<1]);
      if(set[now<<1]!=-inf){
          set[now<<1]+=add[now];
          pset[now<<1]=max(pset[now<<1],set[now<<1]);
      }
      else {
          add[now<<1]+=add[now];
          padd[now<<1]=max(padd[now<<1],add[now<<1]);
      }
      nmx[now<<1|1]+=add[now];
      pmx[now<<1|1]=max(pmx[now<<1|1],nmx[now<<1|1]);
      if(set[now<<1|1]!=-inf){
          set[now<<1|1]+=add[now];
          pset[now<<1|1]=max(pset[now<<1|1],set[now<<1|1]);
      }
      else {
          add[now<<1|1]+=add[now];
          padd[now<<1|1]=max(padd[now<<1|1],add[now<<1|1]);
      }
      add[now]=0;
  }
  if(set[now]!=-inf){
      nmx[now<<1]=set[now];
      pmx[now<<1]=max(pmx[now<<1],nmx[now<<1]);
      set[now<<1]=set[now];
      pset[now<<1]=max(pset[now<<1],set[now<<1]);
      nmx[now<<1|1]=set[now];
      pmx[now<<1|1]=max(pmx[now<<1|1],nmx[now<<1|1]);
      set[now<<1|1]=set[now];
      pset[now<<1|1]=max(pset[now<<1|1],set[now<<1|1]);
      set[now]=-inf;
      add[now<<1]=add[now<<1|1]=0;
  }
  return ;
}
void update_add(int now,int l,int r){
  if(L<=l&&r<=R){
      nmx[now]+=dta;
      pmx[now]=max(pmx[now],nmx[now]);
      if(set[now]!=-inf){
          set[now]+=dta;
          pset[now]=max(pset[now],set[now]);
      }
      else{
          add[now]+=dta;
          padd[now]=max(padd[now],add[now]);
      }
      return ;
  }
  int mid=(l+r)>>1;
  pushdown(now);
  if(L<=mid)update_add(now<<1,l,mid);
  if(mid<R)update_add(now<<1|1,mid+1,r);
  nmx[now]=max(nmx[now<<1],nmx[now<<1|1]);
  pmx[now]=max(pmx[now<<1],pmx[now<<1|1]);
  return ;
}
void update_set(int now,int l,int r){
  if(L<=l&&r<=R){
      nmx[now]=dta;
      pmx[now]=max(pmx[now],dta);
      set[now]=dta;
      pset[now]=max(pset[now],dta);
      add[now]=0;
      return ;
  }
  int mid=(l+r)>>1;
  pushdown(now);
  if(L<=mid)update_set(now<<1,l,mid);
  if(mid<R)update_set(now<<1|1,mid+1,r);
  nmx[now]=max(nmx[now<<1],nmx[now<<1|1]);
  pmx[now]=max(pmx[now<<1],pmx[now<<1|1]);
  return;
}
int query_now(int now,int l,int r){
  if(L<=l&&r<=R){
      return nmx[now];
  }
  int ans=-inf,mid=(l+r)>>1;
  pushdown(now);
  if(L<=mid)ans=max(ans,query_now(now<<1,l,mid));
  if(mid<R)ans=max(ans,query_now(now<<1|1,mid+1,r));
  nmx[now]=max(nmx[now<<1],nmx[now<<1|1]);
  pmx[now]=max(pmx[now<<1],pmx[now<<1|1]);
  return ans;
}
int query_history(int now,int l,int r){
  if(L<=l&&r<=R){
      return pmx[now];
  }
  int ans=-inf,mid=(l+r)>>1;
  pushdown(now);
  if(L<=mid)ans=max(ans,query_history(now<<1,l,mid));
  if(mid<R)ans=max(ans,query_history(now<<1|1,mid+1,r));
  nmx[now]=max(nmx[now<<1],nmx[now<<1|1]);
  pmx[now]=max(pmx[now<<1],pmx[now<<1|1]);
  return ans;
}
int q;
int main(){
  int x,y,z;
  char opt[5];
  read(n);
  for(ri i=1;i<=n;i++)read(num[i]);
  build(1,1,n);
  read(q);
  while(q--){
     scanf("%s",opt);
     read(x),read(y);
     L=x,R=y;
     if(opt[0]=='Q'){
         printf("%d\n",query_now(1,1,n));
     }
     else if(opt[0]=='A'){
         printf("%d\n",query_history(1,1,n));
     }
     else if(opt[0]=='P'){
         read(dta);
         update_add(1,1,n);
     }
     else{
         read(dta);
         update_set(1,1,n);
     }
  }
  return 0;
}

目前洛谷rank 2,在BZOJ上被吊打

posted @ 2018-07-29 21:58  Rye_Catcher  阅读(274)  评论(0编辑  收藏  举报