線段樹+差分——【模板】樹狀陣列2

Louise_Z發表於2017-10-13

題目來源

洛谷P3368【模板】樹狀陣列2
https://www.luogu.org/problem/show?pid=3368


思路

按照差分思想 葉節點記錄這個數與前一個數的差

節點記錄左右兒子(l,r)、區間範圍(x,y)、區間和(num)

查詢x時 遞迴查詢1~x區間和即為數列中第x個數的值

修改x~y的節點加k時 將第x個點加k、第y+1個點減k(即加-k)即可

將第i個點n加v時 對由代表i~i區間的葉節點到根節點的路徑上的節點的num進行修改


程式碼(C++)

#include <cstdio>
using namespace std;
int n,m,c,u,v,w;	long long pre=0;
struct tree
{
	tree *l,*r;
	int x,y;
	long long num;
}*root,*null=new tree();
tree* build(int st,int en);
long long ask(int x,tree *pos);
void change(int x,long long k,tree *pos);
int main()
{
	scanf("%d%d",&n,&m);
	root=build(1,n);	
	for(int i=1;i<=m;++i)
	{
		scanf("%d",&c);
		if(c==1)
		{
			scanf("%d%d%lld",&u,&v,&w);
			change(u,w,root);
			if(v+1<=n)
				change(v+1,-w,root);
		}
		else
		{
			scanf("%d",&u);
			printf("%lld\n",ask(u,root));
		}
	}
	return 0;
}
long long ask(int x,tree *pos)
{
	if(x==pos->y)
		return pos->num;
	if(x>=pos->r->x)
		return ask(x,pos->r)+pos->l->num;
	else
		return ask(x,pos->l);
}
void change(int x,long long k,tree *pos)
{
	if(pos->l==null&&pos->y==x)
	{
		pos->num+=k;
		return ;
	}
	if(x<=pos->l->y)
		change(x,k,pos->l);
	else 
		change(x,k,pos->r);
	pos->num=pos->l->num+pos->r->num;
	return ;
}
tree* build(int st,int en)
{
	tree *pos=new tree();
	pos->x=st;	pos->y=en;
	if(st==en)
	{
		pos->l=null;	pos->r=null;
		scanf("%lld",&pos->num);
		pos->num-=pre;
		pre+=pos->num;
	}
	else
	{
		pos->l=build(st,(st+en)/2);
		pos->r=build((st+en)/2+1,en);
		pos->num=pos->l->num+pos->r->num;
	}
	return pos;
}

相關文章