hdu 3954(线段树的特殊lazy操作-更新时才遍历!)
和经典的线段树区间lazy操作相比,区间传递的是经验系数,每个点对系数的反应是不一样的,所以向下传递的时机有所改变,不但在区间被剖分时要向下释放,在该区间有某个点要升级的时候也要释放,因为此时用区间的lazy值叠加的话会影响结果,所以此时要释放lazy,lazy只有在这个区间的点都没到达升级门槛时才可以叠加。
#include<cstdlib> #include<iostream> #include<cstdio> #include<cmath> #include<cstring> #include<algorithm> #include<set> #include<map> #include<list> #include<queue> #include<stack> #include<vector> #define tree int o,int l,int r #define lson o<<1,l,mid #define rson o<<1|1,mid+1,r #define lo o<<1 #define ro o<<1|1 #define pb push_back #define mp make_pair #define ULL unsigned long long #define LL long long #define inf 1e9 #define eps 1e-7 #define N 10009 using namespace std; int m,n,T,t,q,k; int need[20],ql,qr,e; int ex[N<<2],lel[N<<2],minx[N<<2],lazy[N<<2]; /* ex[o]:最大经验。没有加父节点的lazy[o]. lel[o]:最大水平。 minx[o]:区间升级所需最小的系数!(升级时才向下遍历-减小复杂度) lazy[o]:区间增加的个数。 复杂度:大约O(kn+qlgn); */ void build(tree) { lel[o]=1; ex[o]=lazy[o]=0; minx[o]=need[2]; if(l<r) { int mid=(l+r)>>1; build(lson); build(rson); } } void init() { build(1,1,n); return ; } void pushup(int o)//只需更新父节点! { ex[o]=max(ex[lo],ex[ro]); lel[o]=max(lel[lo],lel[ro]); minx[o]=min(minx[lo],minx[ro]); } void push_down(int o)//push_down时,修改子节点!更方便! { if(lazy[o]) { lazy[lo]+=lazy[o]; lazy[ro]+=lazy[o]; ex[lo]+=lazy[o]*lel[lo]; ex[ro]+=lazy[o]*lel[ro]; minx[lo]-=lazy[o]; minx[ro]-=lazy[o]; lazy[o]=0; } } void update(tree) { if(l==r) { ex[o]+=lel[o]*(e); while(ex[o]>=need[lel[o]+1])lel[o]++; minx[o]=(need[lel[o]+1]-ex[o]+lel[o]-1)/lel[o];//+1 } else { int mid=(l+r)>>1; if(ql<=l&&qr>=r) { if(minx[o]<=e) { push_down(o); if(ql<=mid) update(lson); if(qr>mid) update(rson); pushup(o); } else { ex[o]+=e*lel[o]; lazy[o]+=e; minx[o]-=e; } } else { push_down(o); if(ql<=mid) update(lson); if(qr>mid) update(rson); pushup(o); } } } int query(tree) { if(ql<=l&&qr>=r) { return ex[o]; } else { push_down(o); int mid=(l+r)>>1; int ans=0; if(ql<=mid)ans=max(ans,query(lson)); if(qr>mid)ans=max(ans,query(rson)); pushup(o); return ans; } } int main() { #ifndef ONLINE_JUDGE freopen("ex.in","r",stdin); #endif int ncase=0; need[1]=0; scanf("%d",&T); char str[10]; while(T--) { scanf("%d%d%d",&n,&k,&q); for(int i=2; i<=k; ++i) scanf("%d",&need[i]); need[k+1]=inf; init(); printf("Case %d:\n",++ncase); while(q--) { scanf("%s",str); if(str[0]=='W') { scanf("%d%d%d",&ql,&qr,&e); update(1,1,n); } else { scanf("%d%d",&ql,&qr); printf("%d\n",query(1,1,n)); } } puts(""); } return 0; }