【线段树】区间加区间乘

题目描述

给出序列 a1,a2,…an(0≤ai≤109),有关序列的四种操作:

1. al,al+1,…,ar(1≤l≤r≤n)加上 x(-103≤x≤103)

2. al,al+1,…,ar(1≤l≤r≤n)乘上 x(-103≤x≤103)

3. al,al+1,…,ar(1≤l≤r≤n)变成 x-al,x-al+1 ,…,x-ar(-103≤x≤103)

4. 求:

      

(即求:al+al+1+al+2+…+ar(1≤l≤r≤n)

所有操作均模 109+7

输入格式

第一行包含两个数 n(1≤n≤105)和 m(1≤m≤105),表示序列长度和操作次数

接下来一行包含 n 个数,空格隔开,表示 a1,a2,…,an 。

接下来 m 行,每行为以下 4 种格式之一:

  • 0 l r x ,表示 al,al+1,…,ar 加上 x
  • 1 l r x ,表示 al,al+1,…,ar 乘上 x
  • 2 l r x ,表示 al,al+1,…,ar(1≤l≤r≤n)变成x-al,x-al+1 ,…,x-ar 。
  • 3 l r   ,求:

     

输出格式

对于每次询问,输出单独一行表示答案。

样例数据 1

输入

5 4 
1 2 3 4 5 
0 1 5 1 
1 1 5 -1 
2 1 5 1 
3 5 5

输出

7

代码: 

#include <bits/stdc++.h>
#define LL long long
using namespace std;

const int Max=100010;
const int mod=1e9+7;
int n,m,ans;
int num[Max];
LL add[Max<<2],mul[Max<<2],sum[Max<<2];

inline int get_int()
{
	int x=0,f=1;
	char c;
	for(c=getchar();(!isdigit(c))&&(c!='-');c=getchar());
	if(c=='-') {f=-1;c=getchar();}
	for(;isdigit(c);c=getchar()) x=(x<<3)+(x<<1)+c-'0';
	return x*f;
}

inline void update(LL root) {sum[root] = (LL)(sum[root<<1] + sum[root<<1|1])%mod;}
inline void build(int root,int l,int r)
{
	if(l==r) {sum[root] = num[l],mul[root] = 1;return;}
	int mid = l + r >> 1;
	mul[root] = 1;
	build(root<<1,l,mid),build(root<<1|1,mid+1,r);
	update(root);
}

inline void pushdown(int root,int l,int r,int mid)
{
	if(mul[root] != 1)
	{
  	  sum[root<<1] = (LL)(sum[root<<1] * mul[root])%mod;
	  sum[root<<1|1] = (LL)(sum[root<<1|1] * mul[root])%mod;
	  add[root<<1] = (LL)(add[root<<1]*mul[root])%mod,add[root<<1|1] = (LL)(add[root<<1|1]*mul[root])%mod;
	  mul[root<<1] = (LL)(mul[root<<1]*mul[root])%mod,mul[root<<1|1] = (LL)(mul[root<<1|1]*mul[root])%mod;
	  mul[root] = 1;
    }
	if(add[root] != 0)
	{
	  sum[root<<1] = (LL)(sum[root<<1] + (mid-l+1) * add[root])%mod;
	  sum[root<<1|1] = (LL)(sum[root<<1|1] + (r-mid) * add[root])%mod;
	  add[root<<1] = (LL)(add[root<<1]+add[root])%mod,add[root<<1|1] = (LL)(add[root<<1|1]+add[root])%mod;
	  add[root] = 0;
	}
}

inline void Add(int root,int l,int r,int L,int R,int num)
{
	if(L <= l && R >= r) {sum[root] = (LL)(sum[root] += (r-l+1) * num)%mod,add[root] = (add[root]+num)%mod;return;}
	int mid = l + r >> 1;
	pushdown(root,l,r,mid);
	if(L <= mid) Add(root<<1,l,mid,L,R,num);
	if(R > mid) Add(root<<1|1,mid+1,r,L,R,num); 
	update(root);
}

inline void Mul(int root,int l,int r,int L,int R,int num)
{
	if(L <= l && R >= r)
	{
	  sum[root] = (LL)(sum[root] * num)%mod;
	  add[root] = (LL)(add[root] * num)%mod;
	  mul[root] = (LL)(mul[root] * num)%mod;
	  return;
	}
	int mid = l + r >> 1;
	pushdown(root,l,r,mid);
	if(L <= mid) Mul(root<<1,l,mid,L,R,num);
	if(R > mid) Mul(root<<1|1,mid+1,r,L,R,num); 
	update(root);
}

inline int Q(int root,int l,int r,int L,int R)
{
	if(L <= l && R >= r) return sum[root]%mod;
	int mid = 	l + r >> 1;
	pushdown(root,l,r,mid);
	if(R <= mid) return (LL)Q(root<<1,l,mid,L,R)%mod;
	else if(L > mid) return (LL)Q(root<<1|1,mid+1,r,L,R)%mod;
	else return (LL)(Q(root<<1,l,mid,L,R) + Q(root<<1|1,mid+1,r,L,R))%mod;
}

int main()
{
	n=get_int(),m=get_int();
	for(int i=1;i<=n;i++) num[i]=get_int();
	build(1,1,n);

	for(int i=1;i<=m;i++)
	{
	  int flag = get_int(),L=get_int(),R=get_int();
	  if(flag == 0)
	  {
	    int x=get_int();
	    Add(1,1,n,L,R,x);
	  }
	  if(flag == 1)
	  {
	  	int x=get_int();
	  	Mul(1,1,n,L,R,x);
	  }
	  if(flag == 2)
	  {
	    int x=get_int();
	    Mul(1,1,n,L,R,-1);
	    Add(1,1,n,L,R,x);
	  }
	  if(flag == 3)
	  {
	  	ans = Q(1,1,n,L,R);
	    cout<<(ans%mod+mod)%mod<<"\n";
   	  }
	}

	return 0;
}

猜你喜欢

转载自blog.csdn.net/m0_38083668/article/details/81362092