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 }
View Code

原来的只开一个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 }
View Code

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=3954

posted on 2015-01-08 01:12  xiao_xin  阅读(123)  评论(0编辑  收藏  举报

导航