首页 > 其他 > 详细

cdoj844-程序设计竞赛 (线段树的区间最大连续和)【线段树】

时间:2015-03-27 21:34:05      阅读:351      评论:0      收藏:0      [点我收藏+]

http://acm.uestc.edu.cn/#/problem/show/844

 

程序设计竞赛

Time Limit: 3000/1000MS (Java/Others)     Memory Limit: 65535/65535KB (Java/Others)
 

“你动规无力,图论不稳,数据结构松散,贪心迟钝,没一样像样的,就你还想和我同台竞技,做你的美梦!今天这场比赛,就是要让你知道你是多么的无能!!”

不训练,无以为战。有n项能力是ACM竞赛要求的,训练则能提升,忽略则会荒废。

m天,你能做到如何。

Input

第一行两个整数n,m,分别表示有n项能力要求,共有m天。

第二行n个整数,第i个整数ai表示第i项能力的数值。

接下来m行,每行开始先读入一个整数si,表明这是一次询问还是一次能力变化。

si=0,表明这是一次询问,然后读入两个整数li,ri,表示询问在[li,ri]区间中任选一段连续序列,这段序列中所有能力值之和最大能是多少。

si=1,表明这是一次能力变化,然后读入两个整数xi,wi,表示第xi项能力变为了wi。

1≤n,m≤100000,−10000≤ai≤10000,1≤li≤ri≤n,1≤xi≤n,−10000≤wi≤10000

Output

有多少询问就输出多少行,每行输出一个整数,作为对该询问的回答。

Sample input and output

Sample InputSample Output
4 4
1 2 3 4
0 1 3
1 3 -3
0 2 4
0 3 3
6
4
-3

 

 

思路:

每个节点维护4个值:
summ:此区间内的最大连续和
sum_:该节点以下的节点值得总和
suml:此区间的从左端开始的最大连续和
sumr:此区间的从右端开始的最大连续和
合并区间时,该区间的最大连续和为:max(左子节点的最大连续和,右子节点的最大连续和,左子节点的最大右连续和+右子节点的最大左连续和)

查询时返回一个整节点。因为每次要查询左子节点和右子节点,并且要比较它们的右连续最大和和左连续最大和,所以需要返回整个节点以便求值。

代码:

技术分享
  1 #include <iostream>
  2 #include <cstdio>
  3 #include <cstring>
  4 #include <cmath>
  5 #include <algorithm>
  6 
  7 using namespace std;
  8 
  9 #define INF 0x7fffffff
 10 const int N=100005;
 11 int n,m,a[N];
 12 struct node
 13 {
 14     int left,right;
 15     int sum_,summ,suml,sumr;
 16 }tree[4*N];
 17 
 18 void build(int id,int l,int r);//建一棵线段树
 19 node query_sum(int id,int l,int r);//查询区间和
 20 void update(int id,int pos,int val);//更新位置pos的值
 21 
 22 int main()
 23 {
 24     //freopen("D:\\input.in","r",stdin);
 25     //freopen("D:\\output.out","w",stdout);
 26     int bo,t1,t2;
 27     scanf("%d%d",&n,&m);
 28     for(int i=1;i<=n;i++)
 29         scanf("%d",&a[i]);
 30     build(1,1,n);
 31     for(int i=1;i<=m;i++)
 32     {
 33         scanf("%d%d%d",&bo,&t1,&t2);
 34         if(bo)
 35             update(1,t1,t2);
 36         else{
 37             node tmp=query_sum(1,t1,t2);
 38             printf("%d\n",tmp.summ);
 39         }
 40     }
 41     return 0;
 42 }
 43 void build(int id,int l,int r)
 44 {
 45     tree[id].left=l;
 46     tree[id].right=r;
 47     if(l==r)
 48     {
 49         tree[id].sum_=a[l];
 50         tree[id].summ=a[l];
 51         tree[id].suml=a[l];
 52         tree[id].sumr=a[l];
 53     }
 54     else
 55     {
 56         int mid=(l+r)/2;
 57         build(2*id,l,mid);
 58         build(2*id+1,mid+1,r);
 59         tree[id].sum_=tree[2*id].sum_+tree[2*id+1].sum_;
 60         tree[id].summ=max(max(tree[2*id].summ,tree[2*id+1].summ),(tree[2*id].sumr+tree[2*id+1].suml));
 61         tree[id].suml=max(tree[2*id].suml,tree[2*id].sum_+tree[2*id+1].suml);
 62         tree[id].sumr=max(tree[2*id+1].sumr,tree[2*id].sumr+tree[2*id+1].sum_);
 63     }
 64 }
 65 node query_sum(int id,int l,int r)
 66 {
 67     if(tree[id].left==l&&tree[id].right==r)
 68         return tree[id];
 69     else
 70     {
 71         node tmp,k1,k2;
 72         int flag1=0,flag2=0;
 73         int mid=(tree[id].left+tree[id].right)/2;
 74         if(r<=mid)  return query_sum(2*id,l,r);
 75         if(l>mid)   return query_sum(2*id+1,l,r);
 76         if(l<=mid){
 77             k1=query_sum(2*id,l,mid);
 78             flag1=1;
 79         }
 80         if(r>mid){
 81             k2=query_sum(2*id+1,mid+1,r);
 82             flag2=1;
 83         }
 84         if(flag1&flag2){
 85             tmp.sum_=k1.sum_+k2.sum_;
 86             tmp.suml=max(k1.suml,k1.sum_+k2.suml);
 87             tmp.sumr=max(k2.sumr,k1.sumr+k2.sum_);
 88             tmp.summ=max(max(k1.summ,k2.summ),k1.sumr+k2.suml);
 89         }else{
 90             if(flag1)   tmp=k1;
 91             else  tmp=k2;
 92         }
 93         return tmp;
 94     }
 95 }
 96 void update(int id,int pos,int val)
 97 {
 98     if(tree[id].left==tree[id].right)
 99     {
100         tree[id].sum_=val;
101         tree[id].summ=val;
102         tree[id].suml=val;
103         tree[id].sumr=val;
104     }
105     else
106     {
107         int mid=(tree[id].left+tree[id].right)/2;
108         if(pos<=mid)    update(2*id,pos,val);
109         else update(2*id+1,pos,val);
110         tree[id].sum_=tree[2*id].sum_+tree[2*id+1].sum_;
111         tree[id].summ=max(max(tree[2*id].summ,tree[2*id+1].summ),(tree[2*id].sumr+tree[2*id+1].suml));
112         tree[id].suml=max(tree[2*id].suml,tree[2*id].sum_+tree[2*id+1].suml);
113         tree[id].sumr=max(tree[2*id+1].sumr,tree[2*id].sumr+tree[2*id+1].sum_);
114     }
115 }
View Code

 

cdoj844-程序设计竞赛 (线段树的区间最大连续和)【线段树】

原文:http://www.cnblogs.com/jiu0821/p/4372653.html

(0)
(0)
   
举报
评论 一句话评论(0
关于我们 - 联系我们 - 留言反馈 - 联系我们:wmxa8@hotmail.com
© 2014 bubuko.com 版权所有
打开技术之扣,分享程序人生!