问题描述:有50000个数,想要多次查询这其中任意段数的和,在查询的过程中有可能修改其中一个数的值,然后再多次查询。
思路:一开始想着用DP,但是无奈数据太大,所以才知道可以用线段树。
线段树是基于二叉数的,所以每个节点下面都只可能分成两个叉,每个节点又要储存左边的位置和右边的位置,还有它本身的值和下标,所以用结构体数组。用递归的方法把每个点搜一下,搜到底的时候输入值,再递归回来的时候算每个节点的具体值。改变它的值也是先递归地找到要改变的值,递归回来的时候改变每个节点的值。
#include<iostream>
#include<cstdio>
using namespace std;
struct node
{
int left,right,sum;
int mid() //用来找中间值
{
return (left+right)/2;
}
}segtree[(50000+1)*3];
int ans;
void build(int left,int right,int cur)
{
segtree[cur].left=left;
segtree[cur].right=right;
if(left==right)
{
scanf("%d",&segtree[cur].sum);
return ;
}
else
{
int mid=segtree[cur].mid();
build(left,mid,cur*2);
build(mid+1,right,cur*2+1);
segtree[cur].sum=segtree[cur*2].sum+segtree[cur*2+1].sum;
}
}
void change(int m,int a,int left,int right,int cur)
{
if(left==m&&m==right)
{
segtree[cur].sum=a;
return ;
}
int mid=segtree[cur].mid();
if(m<=mid&&m>=left)
{
change(m,a,left,mid,cur*2);
}
else
{
change(m,a,mid+1,right,cur*2+1);
}
segtree[cur].sum=segtree[cur*2].sum+segtree[cur*2+1].sum;
}
void Find(int left,int right,int l,int r,int cur)
{
int mid=segtree[cur].mid();
if(left<=l&&right<=r)
{
ans+=segtree[cur].sum;
// cout<<ans<<endl;
return;
}
if(l<=mid)
{
Find(left,mid,l,r,cur*2);
}
if(r>=mid)
{
Find(mid+1,right,l,r,cur*2+1);
}
}
int main()
{
int i,n,m,a,l,r;
scanf("%d",&n);
build(1,n,1);
/*
for(i=1;i<=n;i++)
{
printf("%d %d %d\n",segtree[i].left,segtree[i].right,segtree[i].sum);
}
*/
scanf("%d%d",&m,&a);//m为要替换的位置,a为替换的数
change(m,a,1,n,1);
/*
for(i=1;i<=n;i++)
{
printf("%d %d %d\n",segtree[i].left,segtree[i].right,segtree[i].sum);
}
*/
scanf("%d%d",&l,&r);
ans=0;
Find(1,n,l,r,1);
printf("%d\n",ans);
}