线段树第五题,有一点动态规划的意思。代码量较大。
手残残到死啊~~
题目大意:
给一个整数序列编号1~n,n和1相邻。每次更新一个位置上的数,问更新完后区间最大和是多少。注意这个区间不能包括全部的数字。
解题思路:
1、在求区间最大和的时候,在这里只有两种情况:
(1)、不同时包括数字1和数字n,只需要求区间的最大和就行了。
(2)、同时包括数字1和数字n,这时候需要求区间的最小和,用所有数减去这个最小和就行。
2、用线段树来处理问题时,我们需要保存以下这些量:
(1)、当前区间所有数之和,它等于前半个区间所有数之和加后半个区间所有数之和。
(2)、当前区间的最大数的值,可以由前半个区间的和后半个区间最大数的值来决定。
(3)、当前区间的最小数的值,可以由前半个区间的和后半个区间最小数的值来决定。
(4)、当前区间从左开始的最大连续序列值,可由前半个区间的从左开始的最大连续序列值和前半个区间的所有数之和加上后半个区间的从左开始的最大连续序列值决定。
(5)、当前区间从右开始的最大连续序列值,可由后半个区间的从右开始的最大连续序列值和后半个区间的所有数之和加上前半个区间的从右开始的最大连续序列值决定。
(6)、当前区间从左开始的最小连续序列值,可由前半个区间的从左开始的最小连续序列值和前半个区间的所有数之和加上后半个区间的从左开始的最小连续序列值决定。
(7)、当前区间从右开始的最小连续序列值,可由后半个区间的从右开始的最小连续序列值和后半个区间的所有数之和加上前半个区间的从右开始的最小连续序列值决定。
(8)、当前区间的最大连续序列值为前半区间的最大连续序列值、后半区间的最大连续序列值、前半区间从右开始最大连续序列值与后半区间从左开始最大连续序列值之和这三个值中的最大值决定。
(9)、当前区间的最小连续序列值为前半区间的最小连续序列值、后半区间的最小连续序列值、前半区间从右开始最小连续序列值与后半区间从左开始最小连续序列值之和这三个值中的最小值决定。
3、当在最后对线段树更新完成后,根节点的最大连续序列的值不一定就是答案。还有三种意外情况:
(1)、当所有数全部为正数的时候,表现为最大的连续序列值等于所有数之和。这时我们需要输出的是所有数之和与最小数的差。(因为由题意得最大连续序列不能包括所有数字)
(2)、当所有数全部为负数的时候,表现为最小连续序列的值等于所有数之和。这时候我们需要输出最大数。
(3)、当最大连续序列值小于所有数之和减去最小连续序列值时,需要更新最大连续序列值。
看得很头痛的可以结合代码去看。
下面是代码:
#include <stdio.h> const int Max = 100005; struct node1 { int sum,intervalmax,numbermax,intervalmin,numbermin; int lmax,lmin,rmax,rmin; } node[Max<<2]; int max(int a,int b) { if(a<b)a=b; return a; } int min(int a,int b) { if(a>b)a=b; return a; } void PushUp(int tr) { node[tr].sum=node[tr<<1].sum+node[tr<<1|1].sum; node[tr].numbermax=max(node[tr<<1].numbermax,node[tr<<1|1].numbermax); node[tr].numbermin=min(node[tr<<1].numbermin,node[tr<<1|1].numbermin); node[tr].lmax=max(node[tr<<1].sum+node[tr<<1|1].lmax,node[tr<<1].lmax); node[tr].rmax=max(node[tr<<1|1].sum+node[tr<<1].rmax,node[tr<<1|1].rmax); node[tr].lmin=min(node[tr<<1].sum+node[tr<<1|1].lmin,node[tr<<1].lmin); node[tr].rmin=min(node[tr<<1|1].sum+node[tr<<1].rmin,node[tr<<1|1].rmin); node[tr].intervalmax=max(node[tr<<1].intervalmax,node[tr<<1|1].intervalmax); node[tr].intervalmax=max(node[tr].intervalmax,node[tr<<1].rmax+node[tr<<1|1].lmax); node[tr].intervalmin=min(node[tr<<1].intervalmin,node[tr<<1|1].intervalmin); node[tr].intervalmin=min(node[tr].intervalmin,node[tr<<1].rmin+node[tr<<1|1].lmin); } void init(int tr,int num) { node[tr].intervalmin=num; node[tr].intervalmax=num; node[tr].lmax=num; node[tr].lmin=num; node[tr].numbermax=num; node[tr].numbermin=num; node[tr].rmax=num; node[tr].rmin=num; node[tr].sum=num; } void build(int l,int r ,int tr) { if(l==r) { scanf("%d",&node[tr].sum); // printf("***%d\n",l); init(tr,node[tr].sum); return ; } int m=(l+r)>>1; build(l,m,tr<<1); build(m+1,r,tr<<1|1); PushUp(tr); } void update(int p,int num,int l,int r,int tr) { if(l==r) { init(tr,num); return; } int m=(l+r)>>1; if(p<=m)update(p,num,l,m,tr<<1); else update(p,num,m+1,r,tr<<1|1); PushUp(tr); } int Output() { if(node[1].intervalmax<node[1].sum-node[1].intervalmin) { node[1].intervalmax=node[1].sum-node[1].intervalmin; } if(node[1].intervalmax==node[1].sum) { return node[1].sum-node[1].numbermin; } if(node[1].intervalmin==node[1].sum) { return node[1].numbermax; } return node[1].intervalmax; } int main() { int n,m,x,k; while(scanf("%d",&n)!=EOF) { build(1,n,1); scanf("%d",&m); for(int i=0; i<m; i++) { scanf("%d%d",&x,&k); update(x,k,1,n,1); printf("%d\n",Output()); } } return 0; }