线段树板子

线段树,,,(有意思的东西)

区间修改&区间查询

模板题:区间修改&区间查询

#include<bits/stdc++.h>
#define LL long long 
#define sea 1100000
using namespace std;
LL q,n,kk,x,y,xx,yy,s,ans;
struct tree {LL l,r,w,f;}tr[4*sea];
inline LL read()
{
	LL s=0,w=1;char ch=getchar();
	while(ch<'0'||ch>'9'){if(ch=='-')w=-1; ch=getchar();}
	while(ch<='9'&&ch>='0')s=s*10+ch-'0',ch=getchar();
	return s*w;
}
void build(LL ll,LL rr,LL k)//建树 
{
	tr[k].l=ll,tr[k].r=rr;
	if(ll==rr)
	{
		scanf("%lld",&tr[k].w);
		return ;
	}
	LL mid=(ll+rr)/2;
	build(ll,mid,k*2);
	build(mid+1,rr,k*2+1);
	tr[k].w=tr[k*2].w+tr[k*2+1].w;
}
void down(LL k)//下放更新
{
	tr[k*2].f+=tr[k].f;//更新左子树标记
	tr[k*2+1].f+=tr[k].f;//更新右子树标记
	tr[k*2].w+=tr[k].f*(tr[k*2].r-tr[k*2].l+1);//左子树的值
	tr[k*2+1].w+=tr[k].f*(tr[k*2+1].r-tr[k*2+1].l+1);//更新右子树的值
	tr[k].f=0;//切记要清零父亲的懒标记
}
void ask(LL k)
{
	if(tr[k].l>=xx&&tr[k].r<=yy)
	{
		ans+=tr[k].w;//修改
		return ;
	}	
	if(tr[k].f) down(k);
	LL mid=(tr[k].l+tr[k].r)/2;
	if(xx<=mid) ask(k*2);
	if(yy>mid) ask(k*2+1);
}
void change(LL k)
{
	if(tr[k].l>=x&&tr[k].r<=y)
	{
		tr[k].w+=kk*(tr[k].r-tr[k].l+1);
		tr[k].f+=kk;
		return ;
	}
	if(tr[k].f) down(k);
	LL mid=(tr[k].l+tr[k].r)/2;
	if(x<=mid) change(k*2);
	if(y>mid) change(k*2+1);
	tr[k].w=tr[k*2].w+tr[k*2+1].w;// 对值的更新
}
int main()
{
	n=read(); q=read();
	build(1,n,1);//建树
	for(LL i=1;i<=q;i++)
	{
		s=read();
		ans=0;
		if(s==1)//区间修改
		{
			x=read(); y=read(); kk=read();
			change(1);
		}
		else //区间查询
		{
			xx=read(); yy=read();
			ask(1);
			printf("%lld\n",ans);
		}
	}
	return 0;
}

区间修改(加乘)

模板题:区间修改(加乘)

#include<bits/stdc++.h>
#define sea 100010
#define LL long long  
#define left l,mid,k<<1
#define right mid+1,r,k<<1|1
#define lef k<<1 
#define rig k<<1|1
using namespace std;
int n,m,p,s,x,y;
long long sum[sea*4],kk,lazy_ad[sea*4],lazy_mu[sea*4];
inline int read()
{
	int s=0,w=1; char ch=getchar();
	while(ch<'0'||ch>'9'){if(ch=='-')w=-1; ch=getchar();}
	while(ch<='9'&&ch>='0') s=s*10+ch-'0',ch=getchar();
	return s*w;
}
inline LL read_ll()//傻掉的我自己,为什么不用scanf~~~(算了不改了)
{
	LL s=0,w=1; char ch=getchar();
	while(ch<'0'||ch>'9'){if(ch=='-')w=-1; ch=getchar();}
	while(ch<='9'&&ch>='0') s=s*10+ch-'0',ch=getchar();
	return s*w;
}
void build(int l,int r,int k)//建树
{
	lazy_mu[k]=1;//乘最初为一
	if(l==r) sum[k]=read_ll();
	else
	{
		int mid=(l+r)>>1;
		build(left); build(right);
		sum[k]=(sum[lef]+sum[rig])%p;//
	}
	return ;
}
void push(int l,int r,int k,LL a,LL b)//标记
{
	lazy_ad[k]=(lazy_ad[k]*b+a)%p;
	lazy_mu[k]=(lazy_mu[k]*b)%p;
	sum[k]=(sum[k]*b+(r-l+1)*a)%p;
}
void down(int l,int r,int k)//下放
{
	int mid=(l+r)>>1;
	push(left,lazy_ad[k],lazy_mu[k]);
	push(right,lazy_ad[k],lazy_mu[k]);
	lazy_ad[k]=0;	lazy_mu[k]=1;
	return ;
}
void midefy(int l,int r,int k,LL a,LL b)//加乘一块用了
{
	if(x<=l&&r<=y) 	push(l,r,k,a,b);
	elsstation
	{
		if(lazy_ad[k]!=0||lazy_mu[k]!=1) down(l,r,k);
		int mid=(l+r)>>1;
		if(x<=mid) midefy(left,a,b);
		if(y>mid) midefy(right,a,b);
		sum[k]=(sum[lef]+sum[rig])%p;
	}
	return ;
}
LL ask(int l,int r,int k)//询问
{
	if(x<=l&&r<=y) 	return sum[k];
	if(lazy_ad[k]!=0||lazy_mu[k]!=1) down(l,r,k);
	int mid=(l+r)>>1;
	LL ans=0;
	if(x<=mid) ans=(ans+ask(left))%p;
	if(y>mid) ans=(ans+ask(right))%p;
	return ans;
}
int main()
{
	n=read(); m=read(); p=read(); 
	build(1,n,1);
	while(m--)
	{
		s=read();
		if(s==1)//区间加
		{
			x=read(); y=read(); kk=read_ll(); 
			midefy(1,n,1,0,kk);
		}
		else if(s==2)//区间乘
		{
			x=read(); y=read(); kk=read_ll(); 
			midefy(1,n,1,kk,1);
		}
		else//询问
		{
			x=read(); y=read(); 
			printf("%lld\n",ask(1,n,1));
		}
	}
	return 0;
}

单点修改&单点查询

板子题就不找了,代码还是要有的。。

// 单点修改
void alter_one(int k)
{
	if(tr[k].l==tr[k].r)
	{
		tr[k].w+=kk;
		return ;
	}
	int mid=(tr[k].l+tr[k].r)>>1;
	if(x<=mid) alter_one(k*2);
	else alter_one(k*2+1);
	tr[k].w=tr[k*2].w+tr[k*2+1].w;
}
//单点查询
int ask(int k)
{
	if(tr[k].l==tr[k].r)
	{
		ans+=tr[k].w; 
		return ;
	}
	int mid=(tr[k].l+tr[k].r)>>1;
	if(x<=mid) ask(k*2);
	else ask(k*2+1);
	return ans;
} 

具体例题呢,,,,等学完分块再说吧( ̄∇ ̄)

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值