BZOJ1798:[Ahoi2009]Seq 维护序列 线段树

题目大意:维护一个序列,支持3种操作
1.区间上每一个点的值乘一个数
2.区间上每一个点的值加一个数
3.查询一段区间的数值之和


线段树裸题

注意:传乘法标记的时候,初始值要设成1

#include<cmath>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
#define ll long long
const int N=100005;
struct SegMentTree
{ll l,r,mul,plu,sum;}T[N*4];
ll mod,n,m,a[N];
void build(ll x,ll l,ll r)
{
	T[x].l=l,T[x].r=r;
	if(l==r)
	{
		T[x].sum=a[l]%mod;
		return;
	}
	ll mid=(l+r)>>1;
	build(x<<1,l,mid);
	build(x<<1|1,mid+1,r);
	T[x].sum=(T[x<<1].sum+T[x<<1|1].sum)%mod; 
}
void pushdown(ll x)
{
	ll lc=x<<1,rc=x<<1|1;
	ll ls=T[lc].r-T[lc].l+1,rs=T[rc].r-T[rc].l+1;
	T[lc].sum=(T[lc].sum*T[x].mul)%mod,T[rc].sum=(T[rc].sum*T[x].mul)%mod;
	T[lc].sum=(T[lc].sum+T[x].plu*ls)%mod,T[rc].sum=(T[rc].sum+T[x].plu*rs)%mod;
	if(T[x].mul!=1)
	{
 		T[lc].mul=T[lc].mul*T[x].mul%mod;
		T[lc].plu=T[lc].plu*T[x].mul%mod;
		T[rc].mul=T[rc].mul*T[x].mul%mod;
		T[rc].plu=T[rc].plu*T[x].mul%mod;
	}
	if(T[x].plu)
	{
		T[lc].plu=(T[lc].plu+T[x].plu)%mod;
		T[rc].plu=(T[rc].plu+T[x].plu)%mod;
	}
	T[x].mul=1;
	T[x].plu=0;
}
void Modify(ll x,ll l,ll r,ll c,ll flag)
{
	if(T[x].l==l&&T[x].r==r)
	{
		ll len=T[x].r-T[x].l+1,lc=x<<1,rc=x<<1|1;
		if(flag==1)
		{
			T[x].sum=c*T[x].sum%mod;
			T[x].mul=T[x].mul*c%mod;
			T[x].plu=T[x].plu*c%mod;
		}
		if(flag==2)
		{
			T[x].sum=(T[x].sum+c*len)%mod;
			T[x].plu=(T[x].plu+c)%mod;
		}
		return;
	}
	if(T[x].mul!=1||T[x].plu) pushdown(x);
	ll mid=(T[x].l+T[x].r)>>1;
	if(r<=mid) Modify(x<<1,l,r,c,flag);
	else if(l>mid) Modify(x<<1|1,l,r,c,flag);
	else Modify(x<<1,l,mid,c,flag),Modify(x<<1|1,mid+1,r,c,flag);
	T[x].sum=(T[x<<1].sum+T[x<<1|1].sum)%mod;
}
ll Query(ll x,ll l,ll r)
{
	if(T[x].l==l&&T[x].r==r) return T[x].sum%mod;
	if(T[x].mul!=1||T[x].plu) pushdown(x);
	ll mid=(T[x].l+T[x].r)>>1;
	if(r<=mid) return Query(x<<1,l,r);
	else if(l>mid) return Query(x<<1|1,l,r);
	else return (Query(x<<1,l,mid)+Query(x<<1|1,mid+1,r))%mod;
}
int main()
{
	scanf("%lld%lld",&n,&mod);
	for(int i=1;i<=n;i++) scanf("%lld",&a[i]);
    <span style="white-space:pre">	</span>for(int i=1;i<=n*4;i++) T[i].mul=1;
	build(1,1,n);
	scanf("%lld",&m);
	ll o,l,r,c;
	for(int i=1;i<=m;i++)
	{
		scanf("%lld%lld%lld",&o,&l,&r);
		if(o==3) printf("%lld\n",Query(1,l,r));
		else
		{
			scanf("%lld",&c);
			Modify(1,l,r,c%mod,o);
		}
	} 
}


  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值