cdoj844-程序设计竞赛 (线段树的区间最大连续和)【线段树】
http://acm.uestc.edu.cn/#/problem/show/844
?
程序設計競賽
Time Limit: 3000/1000MS (Java/Others) ??? Memory Limit: 65535/65535KB (Java/Others)
Submit?Status“你動規無力,圖論不穩,數據結構松散,貪心遲鈍,沒一樣像樣的,就你還想和我同臺競技,做你的美夢!今天這場比賽,就是要讓你知道你是多么的無能!!”
不訓練,無以為戰。有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
| 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-程序设计竞赛 (线段树的区间最大连续和)【线段树】的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Yelp研发实践:使用服务拆分单块应用
- 下一篇: 【SICP练习】144 练习3.82