数据结构:线段树(自用)

来源:数据结构 —— 线段树_Alex_McAvoy的博客-CSDN博客_结构体线段树

有一说一这个东西真的有点抽象

1.建树

存储方式:结构体

要素:左端点,右端点,要维护的信息,懒标记

(1)每个节点的左孩子区间范围为[l,mid],右孩子为[mid+1,r]

(2)对于结点k,左孩子结点为2*k,右孩子为2*k+1

(3)左右区间端点相等,是叶子结点

结构体形式:

typedef struct node
{
int l,r;
int w;
int mark;
}Tree[n<<2];
Tree tree;

建立过程:

void build(int l,int r,int k)
{
tree[k].l=l;
tree[k].r=r;
  if(l==r)
 {
  scanf("%d",&tree[k].w);
  return;
 }
int mid=(l+r)>>1;
build(l,mid,k<<1);
build(mid+1,r,k<<1|1);
tree[k].w=tree[k<<1].w+tree[k<<1|1].w;
}

2.查询端点

int ans1;
void querythenode(int k,int x)
{
	if(tree[k].l==tree[k].r)
	{
		ans1=tree[k].w;
		return;
	}
	int mid=(tree[k].l+tree[k].r)>>1;
	if(x>=mid)
	{
		querythenode(k<<1|1,x);
	}
	else
	{
	    querythenode(k<<1,x);	
	}
}

3.单点修改(加法)

自顶向下查询所有需求的区间,再自底向上修改

void modifythenode(int k,int x,int v)
{
	if(tree[k].l==tree[k].r)
	{
	 tree[x].w+=v;
	 return;	
	}
	int mid=(tree[k].l+tree[k].r)>>1;
	if(x>=mid)
	{
		modifythenode(k<<1|1,x,v);
	}
	else
	{
	    modifythenode(k<<1,x,v);	
	}
	tree[k].w=tree[k<<1].w+tree[k<<|1].w;
}

4.区间查询(未修改)

(图片来自 Alex_McAvoy的博客)

int ans2=0;
void querytheinterval(int k,int x,int y)
{
	if(x>=tree[k].l&&y<=tree[k]r)
	{
		ans+=tree[k].w;
		return;
	}
	int mid=(tree[k].l+tree[k].r)>>1;
	if(x<=mid)
	{
	    querytheinterval(k<<1,x,y);	
	}
	if(y>=mid)
	{
		querytheinterval(k<<1|1,x,y);
	}
}

5.区间修改

lazy tag(摘自木子喵neko的视频【neko】线段树【算法编程#6】_哔哩哔哩_bilibili):

  将此区间标记,意思是这个区间的值已经更新,但它的子区间还没有更新,更新的信息就是标记里存的值

 1.判断覆盖并打标记。如果要修改的区间完全覆盖当前区间,直接更新这个区间,打上lazy标记

 2.下传清零。如果没有完全覆盖,且当前区间有lazy标记,下传lazy标记到子区间,再清除当前区间的lazy标记

 3.递归左右。如果修改区间和左儿子有交集,搜索左儿子;与右儿子有交集,搜索右儿子

 4.合并更新。最后将当前区间的值更新

 6.区间查询(修改后)

 1.如果要查询的区间完全覆盖当前区间,直接返回当前区间的值

 2.如果没有完全覆盖,下传lazy标记

 3.交左搜左,交右搜右

 4.合并更新

板子题P3372(非结构体AC代码)

#include<stdio.h>
long a[1000000];
long ans[4000000];
long tag[4000000];
void pushup(long p)
{
	ans[p]=ans[p<<1]+ans[p<<1|1];
}
void pushdown(long p,long l,long r,long k)
{
	long mid=(l+r)>>1;
	tag[p<<1]+=k;
	ans[p<<1]+=(mid-l+1)*k;
	tag[p<<1|1]+=k;
	ans[p<<1|1]+=(r-mid)*k;
	tag[p]=0; 
}
void build(long p,long l,long r)
{
	tag[p]=0;
	if(l==r)
	{
	 ans[p]=a[l];
	 return;
	}
	long mid=(l+r)>>1;
	build(p<<1,l,mid);
	build(p<<1|1,mid+1,r);
    pushup(p);	
}
void update(long l,long r,long x,long y,long k,long p)
{
	if(x<=l&&y>=r)
	{
		tag[p]+=k;
		ans[p]+=(r-l+1)*k;
		return;
	}
	pushdown(p,l,r,tag[p]);
	long mid=(l+r)>>1;
	if(x<=mid) update(l,mid,x,y,k,p<<1);
	if(y>mid)  update(mid+1,r,x,y,k,p<<1|1);
	pushup(p);
}
long sumq(long p,long l,long r,long x,long y)
{
	    long res=0;
		if(x<=l&&y>=r)
		{
			return ans[p];
		}
		pushdown(p,l,r,tag[p]);
		long mid=(l+r)>>1;
		if(x<=mid) res+=sumq(p<<1,l,mid,x,y);
		if(y>mid)  res+=sumq(p<<1|1,mid+1,r,x,y);
		return res;
}
int main()
{
 long n,m;
 scanf("%ld %ld",&n,&m);
 long i;
 for(i=1;i<=n;i++)
 {
 	scanf("%ld",&a[i]);
 }	
  build(1,1,n);
  for(i=1;i<=m;i++)
  {
  	int op;
  	scanf("%d",&op);
  	if(op==1)
  	{
  		long x,y,k;
  		scanf("%ld %ld %ld",&x,&y,&k);
  		update(1,n,x,y,k,1);
	}
	if(op==2)
	{
		long x2,y2,temp;
		scanf("%ld %ld",&x2,&y2);
		temp=sumq(1,1,n,x2,y2);
		printf("%ld\n",temp);
	}
  }
  return 0;	
}

板子题P3373

#include<stdio.h>
#include<stdlib.h>
long ans[4000000];
long add[4000000];
long mul[4000000];
long a[1000000];
long mod;
void pushup(long p)
{
	ans[p]=(ans[p<<1]+ans[p<<1|1])%mod;
}
void pushdown(long p,long l,long r)
{
	long mid=(l+r)>>1;
	ans[p<<1]=(ans[p<<1]*mul[p]+add[p]*(mid-l+1))%mod;
	ans[p<<1|1]=(ans[p<<1|1]*mul[p]+add[p]*(r-mid))%mod;
	mul[p<<1]=(mul[p<<1]*mul[p])%mod;
	mul[p<<1|1]=(mul[p<<1|1]*mul[p])%mod;
    add[p<<1]=(add[p<<1]*mul[p]+add[p])%mod;
    add[p<<1|1]=(add[p<<1|1]*mul[p]+add[p])%mod;
	add[p]=0;
	mul[p]=1;
}
void build(long l,long r,long p)
{
	mul[p]=1;
	add[p]=0;
	if(l==r)
	{
		ans[p]=a[l]%mod;
		return;
	}
	long mid=(l+r)>>1;
	build(l,mid,p<<1);
	build(mid+1,r,p<<1|1);
	pushup(p);
}
void update1(long l,long r,long x,long y,long k,long p)
{
	if(l>=x&&r<=y)
	{
		add[p]=(add[p]+k)%mod;
		ans[p]=(ans[p]+(r-l+1)*k)%mod;
		return;
	}
	pushdown(p,l,r);
	long mid=(l+r)>>1;
	if(x<=mid) update1(l,mid,x,y,k,p<<1);
	if(y>mid)  update1(mid+1,r,x,y,k,p<<1|1);
	pushup(p);
}
void update2(long l,long r,long x,long y,long k,long p)
{
	if(l>=x&&r<=y)
	{
		ans[p]=(ans[p]*k)%mod;
		mul[p]=(mul[p]*k)%mod;
		add[p]=(add[p]*k)%mod;
		return;
	}
	pushdown(p,l,r);
	long mid=(l+r)>>1;
	if(x<=mid) update2(l,mid,x,y,k,p<<1);
	if(y>mid)  update2(mid+1,r,x,y,k,p<<1|1);
	pushup(p);
}
long sumq(long l,long r,long x,long y,long p)
{
	long res=0;
	if(l>=x&&r<=y)
	{
		return ans[p];
	}
	pushdown(p,l,r);
	long mid=(l+r)>>1;
	if(x<=mid) res=(res+sumq(l,mid,x,y,p<<1))%mod;
	if(y>mid)  res=(res+sumq(mid+1,r,x,y,p<<1|1))%mod;
	return res;
}
int main()
{
	long n,m;
	scanf("%ld %ld %ld",&n,&m,&mod);
	long i;
	for(i=1;i<=n;i++)
	{
		scanf("%ld",&a[i]);
	}
	build(1,n,1);
	for(i=1;i<=m;i++)
	{
		long x,y,k;
		int op;
		scanf("%d",&op);
		if(op==1)
		{
			scanf("%ld %ld %ld",&x,&y,&k);
			update2(1,n,x,y,k,1);
		}
		if(op==2)
		{
			scanf("%ld %ld %ld",&x,&y,&k);
			update1(1,n,x,y,k,1);
		}
		if(op==3)
		{
			long temp;
			scanf("%ld %ld",&x,&y);
			temp=sumq(1,n,x,y,1);
			printf("%ld\n",temp);
		}
	}
	return 0;
}

离散化

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值