HH大神的神題。只能一直膜拜。。。
從線段樹起步都是從他的博客裡一點一滴的學的。
風格也是仿照他的來的。
然後說題目吧。
題目意思:會有很多波怪獸襲擊,然後也有N個英雄。沒來一波怪獸就派 編號是 L-R 的英雄去迎敵。
每個英雄都會獲得一定的經驗(既是 等級 * 每波的經驗基數 E) 。最後Q操作就是問你 L-R 段中哪一個英雄的經驗最高,並輸出最高值。
開始的時候我有點混淆題目。如果他當時還獲得的經驗足夠他升好幾級的話,那麼當他拿到經驗之後,會馬上升級,然後升一級以後自己的等級改變了。
把他獲得的余下的經驗再按新的等級來計算。那麼就是雪球越滾越大。然後問了 最小公倍數 學長~~~嚯嚯
自己寫的時候,是直接把LAZY (cov 數組) 往下推。然後自己意識到這樣的lazy不能直接疊加 因為多次操作之後他的等級就會變。
之前的標記就沒用了。 那我又想。那每來一個 cov 我就把之前的 cov往下推。 但是顯然 這就如單點更新了。
通過上一段話,應該能明白代碼中的 dis 變量作何用處了
dis 是指區間中 那個需求最少經驗就可以的英雄 所需要的經驗基數。 換句話說 如果這個人都還不能升級的話 那麼這個區間內就不會有人能升級了。
那麼就可以直接加上 cov 。
如果區間內那個人可以升級。以為這這段區間的某一個人的 lev會發生改變 此時我們就要把這個cov 一直往下推。找到那個變了的人。然後再更新區間。
#include <iostream> #include <cstdio> #include <algorithm> #define lson num<<1,s,mid #define rson num<<1|1,mid+1,e #define maxn 10005 using namespace std; int exp[maxn<<2],lev[maxn<<2];//區間最大經驗 區間最大等級 int cov[maxn<<2],dis[maxn<<2];//lazy 標記數組 dis 如上 int ned[15]={0}; int K; void pushup(int num) { exp[num]=max(exp[num<<1],exp[num<<1|1]); lev[num]=max(lev[num<<1],lev[num<<1|1]); dis[num]=min(dis[num<<1],dis[num<<1|1]); } int getlev(int ex)//找到經驗對應的等級 { if(ex>=ned[K-1])return K; for(int i=1;i<=K;i++) { if(ex<ned[i])return i; } } void pushdown(int num) { if(cov[num]) { cov[num<<1|1]+=cov[num]; cov[num<<1]+=cov[num]; exp[num<<1]+=(cov[num]*lev[num<<1]); exp[num<<1|1]+=(cov[num]*lev[num<<1|1]); dis[num<<1]-=cov[num]; dis[num<<1|1]-=cov[num]; cov[num]=0; } } void build(int num,int s,int e) { exp[num]=0; lev[num]=1; cov[num]=0; dis[num]=ned[1]; if(s==e)return; int mid=(s+e)>>1; build(lson); build(rson); } void update(int num,int s,int e,int l,int r,int val) { int mid=(s+e)>>1; if(s==e) { exp[num]+=lev[num]*val; lev[num]=getlev(exp[num]); dis[num]=(ned[lev[num]]-exp[num])/(lev[num])+((ned[lev[num]]-exp[num])%(lev[num])!=0); return ; } if(l<=s && r>=e) { if(val<dis[num]) { exp[num]+=lev[num]*val; dis[num]-=val; cov[num]+=val; return ; } else { pushdown(num); update(lson,s,mid,val); update(rson,mid+1,e,val); pushup(num); return ; } } pushdown(num); if(l<=mid)update(lson,l,r,val); if(r>mid)update(rson,l,r,val); pushup(num); } int query(int num,int s,int e,int l,int r) { if(s>=l && e<=r) { return exp[num]; } pushdown(num); int mid=(s+e)>>1; if(r<=mid)return query(lson,l,r); else if(l>mid)return query(rson,l,r); else return max(query(lson,l,mid),query(rson,mid+1,r)); } int main() { int T,CASE=1; scanf("%d",&T); while(T--) { printf("Case %d:\n",CASE++); int n,qw; scanf("%d%d%d",&n,&K,&qw); for(int i=1;i<K;i++) { scanf("%d",&ned[i]); } ned[K]=1<<30; build(1,1,n); while(qw--) { char tope[5]; scanf("%s",tope); if(tope[0]=='W') { int a,b,c; scanf("%d%d%d",&a,&b,&c); update(1,1,n,a,b,c); } else { int a,b; scanf("%d%d",&a,&b); printf("%d\n",query(1,1,n,a,b)); } } puts(""); } return 0; } /* 5 5 5 999 2 10 15 16 W 1 3 1 W 1 2 1 Q 1 1 */