在我的理解中,线段树就是线段组成的树,越靠近根部的层,线段的长度越长,一个结构体(树的每一个点的左边界,右边界以及要维护的值)和三个函数(build——拆的过程),update(更新的过程,更新的时候要先二分找到最底层的区间,然后需要向上将所有的区间都更新了),query(寻找的过程)。
http://acm.uestc.edu.cn/#/problem/show/844
这个题目的意思就是给一个区间,然后求指定子区间的最大的连续和,在这个过程中还可以不断更新数据。
这个要理清楚结构体里要存的东西,即要维护的东西,是四个值,定义为ssum、sum_、suml,sumr。
#include<iostream>
using namespace std;
int power[100005];
typedef struct Tree
{
int left,right;
int ssum;//此区间内最大连续和
int sum_;//该节点以下的节点值得总和
int suml;//此区间得左端开始的最大连续和
int sumr;//此区间得右端开始的最大连续和
};
Tree tree[100005*4];
int num=0;
void build(int root,int left,int right)
{
tree[root].left=left;
tree[root].right=right;
if(left==right)
{
num=root;
tree[root].ssum=power[left];
tree[root].suml=power[left];
tree[root].sum_=power[left];
tree[root].sumr=power[left];
}
else
{
int mid=(left+right)/2;
build(root*2,left,mid);
build(root*2+1,mid+1,right);
tree[root].sum_=tree[root*2].sum_+tree[root*2+1].sum_;
//sum_代表的是这个区间的和,那么只要把左区间的和以及右区间的和给加起来就好
tree[root].ssum=max(max(tree[root*2].ssum,tree[root*2+1].ssum),(tree[root*2].sumr+tree[root*2+1].suml));
//这个是比较关键的,已知一个区间的左右区间的最大连续和怎么合并,要么就是左区间的最大连续和,要么就是右区间的最大连续和,要么就是左区间的最大右起连续和+右区间的最大左起连续和
tree[root].suml=max(tree[root*2].suml,tree[2*root].sum_+tree[2*root+1].suml);
//该区间从左边起的最大连续和,要么就是左子区间的最大左起连续和要么就是左子区间的和+右子区间的最大左起连续和,这也是我们维护一个区间的和的原因。
tree[root].sumr=max(tree[root*2+1].sumr,tree[2*root].sumr+tree[2*root+1].sum_);
}
}
Tree query_sum(int root,int left,int right)
{
if(tree[root].left==left&&tree[root].right==right)
return tree[root];
else
{
int mid=(tree[root].left+tree[root].right)/2;
if(right<=mid)
return query_sum(2*root,left,right);
if(left>mid)
return query_sum(2*root+1,left,right);
Tree k1,k2,temp;
k1=query_sum(2*root,left,mid);
k2=query_sum(2*root+1,mid+1,right);
temp.sum_=k1.sum_+k2.sum_;
temp.ssum=max(max(k1.ssum,k2.ssum),k1.sumr+k2.suml);
temp.suml=max(k1.suml,k1.sum_+k2.suml);
temp.sumr=max(k2.sumr,k1.sumr+k2.sum_);
return temp;
}
}
void update(int root,int pos,int value)
//更新函数就是先不断二分找到位置,然后要像建树一样合并区间
{
if(tree[root].left==tree[root].right)
{
tree[root].ssum=value;
tree[root].suml=value;
tree[root].sum_=value;
tree[root].sumr=value;
}
else
{
int mid=(tree[root].left+tree[root].right)/2;
if(pos<=mid)
update(2*root,pos,value);
else
update(2*root+1,pos,value);
tree[root].sum_=tree[root*2].sum_+tree[root*2+1].sum_;
tree[root].ssum=max(max(tree[root*2].ssum,tree[root*2+1].ssum),(tree[root*2].sumr+tree[root*2+1].suml));
tree[root].suml=max(tree[root*2].suml,tree[2*root].sum_+tree[2*root+1].suml);
tree[root].sumr=max(tree[root*2+1].sumr,tree[2*root].sumr+tree[2*root+1].sum_);
}
}
int main()
{
int n,m;
scanf("%d %d",&n,&m);
int i;
for(i=1;i<=n;i++)
scanf("%d",&power[i]);
build(1,1,n);
for(i=0;i<m;i++)
{
int type,loperate,roperate;
scanf("%d%d%d",&type,&loperate,&roperate);
if(type)
{
update(1,loperate,roperate);
}
else
{
Tree temp=query_sum(1,loperate,roperate);
printf("%d\n",temp.ssum);
}
}
return 0;
}
https://vjudge.net/contest/208944#problem/J
#include<iostream>
using namespace std;
long long power[100005];
typedef struct Tree
{
int left,right;
long long ssum;//此区间内最大连续和
long long sum_;//该节点以下的节点值得总和
long long suml;//此区间得左端开始的最大连续和
long long sumr;//此区间得右端开始的最大连续和
};
Tree tree[100005*4];
int num=0;
void build(int root,int left,int right)
{
tree[root].left=left;
tree[root].right=right;
if(left==right)
{
num=root;
tree[root].ssum=power[left];
tree[root].suml=power[left];
tree[root].sum_=power[left];
tree[root].sumr=power[left];
}
else
{
int mid=(left+right)/2;
build(root*2,left,mid);
build(root*2+1,mid+1,right);
tree[root].sum_=tree[root*2].sum_+tree[root*2+1].sum_;
tree[root].ssum=max(max(tree[root*2].ssum,tree[root*2+1].ssum),(tree[root*2].sumr+tree[root*2+1].suml));
tree[root].suml=max(tree[root*2].suml,tree[2*root].sum_+tree[2*root+1].suml);
tree[root].sumr=max(tree[root*2+1].sumr,tree[2*root].sumr+tree[2*root+1].sum_);
}
}
Tree query_sum(int root,int left,int right)
{
if(tree[root].left>=left&&tree[root].right<=right)
return tree[root];
else
{
int mid=(tree[root].left+tree[root].right)/2;
if(right<=mid)
return query_sum(2*root,left,right);
if(left>mid)
return query_sum(2*root+1,left,right);
Tree k1,k2,temp;
k1=query_sum(2*root,left,mid);
k2=query_sum(2*root+1,mid+1,right);
temp.sum_=k1.sum_+k2.sum_;
temp.ssum=max(max(k1.ssum,k2.ssum),k1.sumr+k2.suml);
temp.suml=max(k1.suml,k1.sum_+k2.suml);
temp.sumr=max(k2.sumr,k1.sumr+k2.sum_);
return temp;
}
}
void update(int root,int pos,int value)
{
if(tree[root].left==tree[root].right)
{
tree[root].ssum=value;
tree[root].suml=value;
tree[root].sum_=value;
tree[root].sumr=value;
}
else
{
int mid=(tree[root].left+tree[root].right)/2;
if(pos<=mid)
update(2*root,pos,value);
else
update(2*root+1,pos,value);
tree[root].sum_=tree[root*2].sum_+tree[root*2+1].sum_;
tree[root].ssum=max(max(tree[root*2].ssum,tree[root*2+1].ssum),(tree[root*2].sumr+tree[root*2+1].suml));
tree[root].suml=max(tree[root*2].suml,tree[2*root].sum_+tree[2*root+1].suml);
tree[root].sumr=max(tree[root*2+1].sumr,tree[2*root].sumr+tree[2*root+1].sum_);
}
}
int main()
{
int n;
scanf("%d",&n);
int i;
for(i=1;i<=n;i++)
scanf("%lld",&power[i]);
build(1,1,n);
//for(i=1;i<=num;i++)
// cout<<tree[i].left<<" "<<tree[i].right<<" "<<tree[i].ssum<<" "<<tree[i].sum_<<" "<<tree[i].suml<<" "<<tree[i].sumr<<endl;
for(i=0;i<n;i++)
{
long long x;
scanf("%lld",&x);
update(1,x,-10000000000000000);
Tree temp=query_sum(1,1,n);
if(temp.ssum>=0)
printf("%lld\n",temp.ssum);
else
printf("0\n");
}
return 0;
}