【树形结构】训练题M - 维护序列

题意

一种序列,三种操作。

1.从t到g 每一个乘c

2.从t到g 每一个加c

3.查询区间和

思路

这一题的变化在于要注意取模。

其次,对于乘和加,需要放置两个标记,下放lazy的时候写成一个pushdown,并且做乘运算的时候,加法lazy也要有相应的改变。还有就是lazy和ans值的改变与传统线段树模板的不同

代码

#include<iostream>
#include<cmath>
#include<stack>
#include<map>
#include<queue>
#include<cstdio>
#include<vector>
#include<cstring>
#include<algorithm>

#define Endl "\n" 
typedef long long ll;
const int maxn=1e6;
const int mod=1e9+7;
using namespace std;

ll n,P,M;
int key,t,g,c;
ll ans[maxn<<2];
ll lazyjia[maxn<<2];
ll lazycheng[maxn<<2];
inline ll read()
{
	ll x = 0, f = 1; char ch; ch = getchar();
	while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
	while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
	return x*f;
}
void PushUp(int rt)
{
    ans[rt]=(ans[rt<<1]+ans[rt<<1|1])%P;
    return ;
}

//建树
void Build(int l,int r,int rt)
{
	lazycheng[rt]=1;
//	lazyjia[rt]=0;
    if (l==r)
    {
        ans[rt]=read()%P;
        return;
    }
    int mid=(l+r)>>1;
    int left=rt<<1;
    int right=left|1;
    Build(l,mid,left);
    Build(mid+1,r,right);
    PushUp(rt);
    return ;
}
void PushDown(int rt,int ln,int rn)//ln表示左子树元素结点个数,rn表示右子树结点个数
{
	
    if (lazycheng[rt]!=1)
    {
    	ll left=rt<<1;
    	ll right=left|1;
    	lazyjia[left]=(lazyjia[left]*lazycheng[rt])%P;
    	lazyjia[right]=(lazyjia[right]*lazycheng[rt])%P;
        lazycheng[left]=(lazycheng[rt]*lazycheng[left])%P;
        lazycheng[right]=(lazycheng[rt]*lazycheng[right])%P;
        ans[left]=(lazycheng[rt]*ans[left])%P;
        ans[right]=(lazycheng[rt]*ans[right])%P;
        lazycheng[rt]=1;
  //      return ;
    }
    
    if(lazyjia[rt])
    {
    	ll left=rt<<1;
    	ll right=left|1;
    	ans[left]=(ans[left]+lazyjia[rt]*ln)%P;
    	ans[right]=(ans[right]+lazyjia[rt]*rn)%P;
    	lazyjia[left]=(lazyjia[left]+lazyjia[rt])%P;
    	lazyjia[right]=(lazyjia[right]+lazyjia[rt])%P;
    	lazyjia[rt]=0;
    //	return ;
	}
	return ;
}
void add(int L,int R,int C,int l,int r,int rt)
{
	if(R<l||L>r)
		return ;
    if (L<=l&&r<=R)
    {
        ans[rt]=(ans[rt]+(r-l+1)*C)%P;
        lazyjia[rt]=(lazyjia[rt]+C)%P;
 //       cout<<"ans "<<rt<<" "<<ans[rt]<<Endl;
        return;
    }
    int mid=(l+r)>>1;
    int left=rt<<1;
    int right=left|1;
    PushDown(rt,mid-l+1,r-mid);
    if (L<=mid) add(L,R,C,l,mid,left);
    if (R>mid) add(L,R,C,mid+1,r,right);
   PushUp(rt);
 //   for(int i=1;i<=13;i++)
//				cout<<ans[i]<<" ";
//			cout<<Endl;
   return ;
}
void multiply(int L,int R,int C,int l,int r,int rt)
{
	if(R<l||L>r)
		return ;
    if (L<=l&&r<=R)
    {
        ans[rt]=(C*ans[rt])%P;
        lazycheng[rt]=(lazycheng[rt]*C)%P;
        lazyjia[rt]=(lazyjia[rt]*C)%P;
  //      cout<<"ans "<<rt<<" "<<ans[rt]<<Endl;
        return ;
    }
    int mid=(l+r)>>1;
    int left=rt<<1;
    int right=left|1;
    PushDown(rt,mid-l+1,r-mid);
    if (L<=mid) multiply(L,R,C,l,mid,left);
    if (R>mid) multiply(L,R,C,mid+1,r,right);
   PushUp(rt);
//   for(int i=1;i<=13;i++)
//				cout<<ans[i]<<" ";
//			cout<<Endl;
   return ;
}
ll Query(int L,int R,int l,int r,int rt)
{
	if(L>r||R<l)
		return 0;
    if (L<=l&&r<=R)
        return ans[rt];
    int mid=(l+r)>>1;
    int left=rt<<1;
    int right=left|1;
    PushDown(rt,mid-l+1,r-mid);//若更新只有点更新,不需要这句
    ll ANS=0;
    if (L<=mid) ANS+=Query(L,R,l,mid,left)%P;
    if (R>mid) ANS+=Query(L,R,mid+1,r,right)%P;
    return ANS%P;

} 
 

int main()
{
	n=read(),P=read();
	Build(1,n,1);
//	for(int i=0;i<10;i++)
//				cout<<ans[i]<<" ";
	M=read();
	while(M--)
	{
		key=read(),t=read(),g=read();
		if(key==1)
		{
			c=read();
			multiply(t,g,c,1,n,1); 

		}
		else if(key==2)
		{
			c=read();
			add(t,g,c,1,n,1);
	
		}
		else
		{
			cout<<Query(t,g,1,n,1)%P<<Endl;
		}
	}
	return 0;
}

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值