線段樹維護區間最大連續和
阿新 • • 發佈:2018-12-24
在我的理解中,線段樹就是線段組成的樹,越靠近根部的層,線段的長度越長,一個結構體(樹的每一個點的左邊界,右邊界以及要維護的值)和三個函式(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;
}
#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;
}