【模板】吉司机线段树 HDU 5306 Gorgeous Sequence

匿名 (未验证) 提交于 2019-12-03 00:03:02

也叫小清新线段树,用于解决区间最值修改问题

此题就作为模板好了,模板的话写法是比较精妙的

#include<bits/stdc++.h> using namespace std;  #define go(i,a,b) for(int i=a;i<=b;++i) #define com(i,a,b) for(int i=a;i>=b;--i) #define mem(a,b) memset(a,b,sizeof(a)) #define int long long  const int N=1000000+10;  int n,m,a[N]; struct tree{//其实更新标记和最大值可以二合一 //若更新成功则最大值就是标记,若没有更新下传最大值也不会更新子区间      int l,r,mx,se,c,sum;     #define l(i) t[i].l     #define r(i) t[i].r     #define c(i) t[i].c     #define mx(i) t[i].mx     #define se(i) t[i].se     #define sum(i) t[i].sum     #define ls rt<<1     #define rs rt<<1|1 }t[N<<2];  template<typename T>void read(T &x){     x=0;char c=getchar(),f=1;     while(!isdigit(c)){ if(c=='-') f=-1; c=getchar(); }     while(isdigit(c)){ x=x*10+c-'0'; c=getchar(); }     x*=f; }  void push_up(int rt){     sum(rt)=sum(ls)+sum(rs);     mx(rt)=max(mx(ls),mx(rs));     se(rt)=max(se(ls),se(rs));     if(mx(ls)!=mx(rs)) se(rt)=max(se(rt),min(mx(ls),mx(rs)));     if(mx(rt)==mx(ls)) c(rt)+=c(ls);     if(mx(rt)==mx(rs)) c(rt)+=c(rs);     //注意啦,此处写法十分精妙。     //若mx(ls)==mx(rs) c(rt)=c(ls)+c(rs)  }  void update(int rt,int z){//在下传标记时z不可能<=se(rt),因为Z>se(rt的祖先节点)>=se(rt)     if(z>=mx(rt)) return;     sum(rt)-=(mx(rt)-z)*c(rt);     mx(rt)=z; }  void build(int rt,int l,int r){     l(rt)=l,r(rt)=r;     if(l==r){         mx(rt)=sum(rt)=a[l],se(rt)=-1;         c(rt)=1;         return;     }     int mid=l+r>>1;     build(ls,l,mid);     build(rs,mid+1,r);     push_up(rt); }  void push_down(int rt){     update(ls,mx(rt)),update(rs,mx(rt)); }  void change(int rt,int x,int y,int z){     if(z>=mx(rt)) return;//剪枝,如果比大区间的最大值还大,自然不可能修改小区间      if(l(rt)>=x&&r(rt)<=y&&z>se(rt)){         update(rt,z);         return;     }     int mid=l(rt)+r(rt)>>1;     push_down(rt);     if(x<=mid) change(ls,x,y,z);     if(y>mid) change(rs,x,y,z);     push_up(rt); }  int getmax(int rt,int x,int y){     if(l(rt)>=x&&r(rt)<=y) return mx(rt);     push_down(rt);     int ans=0;     int mid=l(rt)+r(rt)>>1;     if(x<=mid) ans=max(ans,getmax(ls,x,y));     if(y>mid) ans=max(ans,getmax(rs,x,y));     return ans; }  int getsum(int rt,int x,int y){     if(l(rt)>=x&&r(rt)<=y) return sum(rt);     push_down(rt);     int ans=0,mid=l(rt)+r(rt)>>1;     if(x<=mid) ans+=getsum(ls,x,y);     if(y>mid) ans+=getsum(rs,x,y);     return ans; }  void work(){     read(n),read(m);     go(i,1,n) read(a[i]);     build(1,1,n);     int op,x,y,z;     while(m--){         read(op),read(x),read(y);         if(!op) read(z),change(1,x,y,z);         else if(op==1) printf("%lld\n",getmax(1,x,y));         else if(op==2) printf("%lld\n",getsum(1,x,y));     } }  signed main(){     //freopen("data.txt","r",stdin);     //freopen("out.txt","w",stdout);     int T;read(T);     while(T--) work();     return 0; }
标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!