hdu3954 线段树 打怪升级,等级不同加经验不同,询问区间经验值最高
或许,是我理解错了。
完全可以把大白书上的maintain当成pushup。
其实只要完全理解了,什么姿势都能把线段树打出来。
话题回到这道题目,开一个maxv二维数组,记录等级为i的人在该区间最大经验,然后用线段树(levelup)进行升级。
1 #include<stdio.h> 2 #include<string.h> 3 #include<algorithm> 4 using namespace std; 5 int maxv[15][50005],addv[50005],need[15],k; 6 void pushup(int o) 7 { 8 for (int i=1;i<=k;i++) 9 maxv[i][o]=max(maxv[i][o*2],maxv[i][o*2+1]); 10 } 11 void pushdown(int o) 12 { 13 if (addv[o]){ 14 addv[o*2]+=addv[o]; 15 addv[o*2+1]+=addv[o]; 16 for (int i=1;i<=k;i++){ 17 if (maxv[i][o*2]!=-1) maxv[i][o*2]+=addv[o]*i; 18 if (maxv[i][o*2+1]!=-1) maxv[i][o*2+1]+=addv[o]*i; 19 } 20 addv[o]=0; 21 } 22 } 23 void levelup(int o,int l,int r,int now) 24 { 25 if (l==r){ 26 while (now<k&&maxv[now][o]>=need[now+1]){ 27 maxv[now+1][o]=maxv[now][o]; 28 maxv[now][o]=-1; 29 now++; 30 } 31 } 32 else{ 33 int mid=l+(r-l)/2; 34 pushdown(o); 35 if (maxv[now][o*2]>=need[now+1]) levelup(o*2,l,mid,now); 36 if (maxv[now][o*2+1]>=need[now+1]) levelup(o*2+1,mid+1,r,now); 37 pushup(o); 38 } 39 } 40 void update(int o,int l,int r,int y1,int y2,int v) 41 { 42 if (y1<=l&&y2>=r){ 43 addv[o]+=v; 44 for (int i=k;i>=1;i--){ 45 if (maxv[i][o]!=-1) maxv[i][o]+=i*v; 46 if (i<k&&maxv[i][o]>=need[i+1]) levelup(o,l,r,i); 47 } 48 } 49 else{ 50 pushdown(o); 51 int mid=l+(r-l)/2; 52 if (y1<=mid) update(o*2,l,mid,y1,y2,v); 53 if (y2>mid) update(o*2+1,mid+1,r,y1,y2,v); 54 pushup(o); 55 } 56 } 57 int query(int o,int l,int r,int y1,int y2) 58 { 59 int tmp=0,mid=l+(r-l)/2; 60 if (y1<=l&&y2>=r){ 61 for (int i=k;i>=1;i--) 62 if (maxv[i][o]!=-1) return maxv[i][o]; 63 } 64 pushdown(o); 65 if (y1<=mid) tmp=max(tmp,query(o*2,l,mid,y1,y2)); 66 if (y2>mid) tmp=max(tmp,query(o*2+1,mid+1,r,y1,y2)); 67 //pushup(o); 68 return tmp; 69 } 70 int main() 71 { 72 int T,t,n,m,i,l,r,v; 73 char ch[5]; 74 scanf("%d",&T); 75 for (t=1;t<=T;t++) 76 { 77 scanf("%d%d%d",&n,&k,&m); 78 memset(addv,0,sizeof(addv)); 79 memset(maxv,-1,sizeof(maxv)); 80 memset(maxv[1],0,sizeof(maxv[1])); 81 need[1]=0; 82 for (i=2;i<=k;i++) scanf("%d",&need[i]); 83 printf("Case %d:\n",t); 84 for (i=1;i<=m;i++) 85 { 86 scanf("%s",ch); 87 if (ch[0]=='W'){ 88 scanf("%d%d%d",&l,&r,&v); 89 update(1,1,n,l,r,v); 90 } 91 else{ 92 scanf("%d%d",&l,&r); 93 printf("%d\n",query(1,1,n,l,r)); 94 } 95 } 96 printf("\n"); 97 } 98 return 0; 99 }
原来的只开一个ok数组为何超时,只要每次加1升级需要10000就跪了。
tle代码:
1 #include<stdio.h> 2 #include<iostream> 3 #include<string.h> 4 #include<algorithm> 5 using namespace std; 6 int k,need[55],level[50005],exp[50005]; 7 int maxv[50005],addv[50005],ok[50005]; 8 void update(int o,int l,int r,int y1,int y2,int v) 9 { 10 if (l==r){ 11 exp[l]+=level[l]*v; 12 while (level[l]<k&&exp[l]>=need[level[l]+1]) level[l]++; 13 addv[o]=exp[l]; 14 ok[o]=(level[l]>=k); 15 } 16 else{ 17 int mid=l+(r-l)/2; 18 if (ok[o]&&y1<=l&&y2>=r) addv[o]+=k*v; 19 else{ 20 if (y1<=mid) update(o*2,l,mid,y1,y2,v); 21 if (y2>mid) update(o*2+1,mid+1,r,y1,y2,v); 22 ok[o]=(ok[o*2]&&ok[o*2+1]); 23 } 24 } 25 maxv[o]=0; 26 if (r>l) maxv[o]=max(maxv[o*2],maxv[o*2+1]); 27 maxv[o]+=addv[o]; 28 } 29 int query(int o,int l,int r,int y1,int y2,int add) 30 { 31 int mid=l+(r-l)/2,tmp=0; 32 if (y1<=l&&y2>=r) return add+maxv[o]; 33 else{ 34 if (y1<=mid) tmp=max(tmp,query(o*2,l,mid,y1,y2,add+addv[o])); 35 if (y2>mid) tmp=max(tmp,query(o*2+1,mid+1,r,y1,y2,add+addv[o])); 36 return tmp; 37 } 38 } 39 int main() 40 { 41 int T,t,n,m,i,l,r,v; 42 char ch[5]; 43 scanf("%d",&T); 44 for (t=1;t<=T;t++) 45 { 46 scanf("%d%d%d",&n,&k,&m); 47 need[1]=0; need[k+1]=0x3f3f3f3f; 48 for (i=2;i<=k;i++) scanf("%d",&need[i]); 49 for (i=1;i<=n;i++) level[i]=1; 50 memset(exp,0,sizeof(exp)); 51 memset(maxv,0,sizeof(maxv)); 52 memset(addv,0,sizeof(addv)); 53 memset(ok,0,sizeof(ok)); 54 printf("Case %d:\n",t); 55 for (i=1;i<=m;i++) 56 { 57 scanf("%s",ch); 58 if (ch[0]=='W'){ 59 scanf("%d%d%d",&l,&r,&v); 60 update(1,1,n,l,r,v); 61 } 62 else{ 63 scanf("%d%d",&l,&r); 64 printf("%d\n",query(1,1,n,l,r,0)); 65 } 66 } 67 printf("\n"); 68 } 69 return 0; 70 }