线段树初级

今天做到一题是线段树题,在此补充一下我自己缺失的知识点
首先介绍一个写的贼好的博客
https://oi-wiki.org/ds/seg/
准备每天看一篇,每天增加一个小的知识点。
今天是线段树
首先是建树的过程,因为鄙人画图技术有限,所以大家还是参考那个博客的讲解吧,这里主要是一些代码

void buildTree(int l,int r,int n)
{
	if(l==r)
{
	b[n]=value;
	return ;
}
	int m=(l+r)/2;
	buildTree(l,m,n<<1);
	buildTree(m+1,r,n<<1|1);
	tree[n]=tree[n*2]+tree[n<<2|1];
}

建好树之后,会出现一个问题就是tree的数组开多大,答案是4*n,上述链接中有提到过这个问题。
下面我们就要实现

***

1.区间查询

区间查询,可以查询到某一段区间内的最值问题,还有区间和问题。


首先是查找值的问题

int search(int i,int l,int r)
{

	if(tree[i].l>=l&&tree[i].r<=r)
	{
		return tree[i].value;
	}
	if(tree[i].l<l||tree[i].r>r)
	{
		return 0;
	} 
	if(tree[i*1].r>=l)
	s+=search(i<<1,l,r);
	if(tree[i<<1|1].l<=r)
	s+=search(i<<1|1,l,r);
	
	return s;
}

这是查找区间和的问题,时间复杂度大概是o(logn)
单点修改

void change(int i,int dis)
{
	if(tree[i].l==tree[i].r)
{
	tree[i].sum+=k;
	return ;
}
	if(dis<tree[i<<1].r)
	change(i<<1,dis);
	if(dis>=tree[i<<|1].l)
	change(i<<1|1,dis);
	tree[i].sum=tree[i<<1].sum+tree[i<<1|1].sum;
}

注意单点修改时一定要更新树上的所有信息
区间修改

void search(int i,int l,int r,int k)
{
	if(tree[i].l>=l&&tree[i].r<=r)
{
	tree[i].sum+=k;
	return ;
}
	if(tree[i<<1].r>=l)
	search(i<<1,l,r,k);
	 if(tree[i<<1|1].l<=r)
	search(i<<1|1,l,r,k);

}

这段代码给的不太行,
然后 我就去做题了,做了
传送门:

https://www.luogu.com.cn/problem/P3374

我发现光有这些理论那是不可以的
还得实践,实践出真知啊

#include
using namespace std;
int maxn=2*1e6;
int a1,b,c;
int a[500010];
int s=0;
int ans=0; 
typedef struct node
{
	int l;
	int r;
	int value;
}Node;
Node tree[2000010];
    void build(int left,int right,int index)
    {
        tree[index].l=left;
        tree[index].r=right;
           if(left==right)
            return ;
        int mid=(right+left)/2;
        build(left,mid,index*2);
        build(mid+1,right,index*2+1);
    }
    int add(int index)
    {
        if(tree[index].l==tree[index].r)
        {
            //cout<
            tree[index].value=a[tree[index].r];
            return tree[index].value;
        }
        tree[index].value=add(index*2)+add(index*2+1);
        return tree[index].value;
    }

void change(int i,int k,int dis)
{

	//cout<<"i:"<
	//cout<
	if(tree[i].l==tree[i].r)
	
	
	{
      tree[i].value+=k;
		return ;
	}
	if(dis>=tree[i<<1|1].l)
	change(i<<1|1,k,dis);
	if(dis<=tree[i<<1].r)
	change(i<<1,k,dis);
	tree[i].value=tree[i<<1].value+tree[i<<1|1].value;

}
 void search(int i,int l,int r)
    {
        //cout<
        if(tree[i].l>=l && tree[i].r<=r)
        {
            ans+=tree[i].value;
            return ;
        }
        if(tree[i*2].r>=l)
            search(i*2,l,r);
        if(tree[i*2+1].l<=r)
            search(i*2+1,l,r);
    }
int main()
{
	int n,m;
	scanf("%d%d",&n,&m);
	for(int i=1;i<=n;i++)
	{
	scanf("%d",&a[i]);
	}
//	cout<<" 是我的问题吗"<
	build(1,n,1);
	add(1);
//	cout<<"哦买噶"<
	for(int i=0;i<m;i++)
	{
			scanf("%d%d%d",&a1,&b,&c);
		if(a1==1)
		change(1,c,b);
		if(a1==2)
		{
		ans=0;
		search(1,b,c);
			
		printf("%d\n",ans);
		}
	}
	
}

AC代码,
这道题我调了一天,首先是tree数组的大小一定要开好,其次就是,建树,应如上面代码那样写,要不然,就会tle,时间复杂度会增加。
线段树模板2
这个区间修改和单值查询,有一个技巧,就是对于树可以不直接调用add函数,因为其输出时,就只有一个数字,因此方便计算,可以省去一个add函数。

#include
using namespace std;
typedef struct node
{
	int l,r;
	int value;
}Node;
Node tree[2000010];
int a[500010];
int a1,b,c;
int ans=0;
void BuildTree(int l,int r,int i)
{
	tree[i].l=l;
	tree[i].r=r;
	if(tree[i].l==tree[i].r)
	{
		return ;
	}
	int mid=(l+r)/2;
	BuildTree(l,mid,i<<1);
	BuildTree(mid+1,r,i<<1|1);
}
void change(int l,int r,int i,int k)
{
	if(tree[i].l>=l&&tree[i].r<=r)
	{
		tree[i].value+=k;
		return ;
	}
	if(tree[i<<1].r>=l)
	change(l,r,i<<1,k);
	if(tree[i<<1|1].l<=r)
	change(l,r,i<<1|1,k);

}
void search(int dis,int i)
{	ans+=tree[i].value;
	if(tree[i].l==tree[i].r)
	{
	
		return ;
	}
	if(dis>=tree[i<<1|1].l)
	search(dis,i<<1|1);
	if(dis<=tree[i<<1].r)
	search(dis,i<<1);
}
int main()
{
	int n,m;
scanf("%d%d",&n,&m);
	for(int i=1;i<=n;i++)
	{
		scanf("%d",&a[i]);
	}
	BuildTree(1,n,1);
	for(int i=0;i<m;i++)
	{int k;
		scanf("%d",&a1); 
		if(a1==1)
		{
		scanf("%d%d%d",&b,&c,&k);
			change(b,c,1,k);
				
		}
		if(a1==2)
		{
		scanf("%d",&b);
			ans=0;
			search(b,1);
			int t=0;
			t=ans+a[b];
			printf("%d\n",t);
		}
	}
}

因为忘记建树,wa了好久,awsl

你可能感兴趣的:(acm)