我呃呃
这个题主要的思想就是懒标记。。。(然而我之前并没有写过,结果就因为理解出现偏差,就写了2个小时)
懒标记与你当前线段树节点没关系,是维护子树的
,,,我就认为懒标记也维护了自己。。
结果就翻车了(创造了一个线段树套队列的神奇结构。。。。。。。我太弱了(不过不算空间的话,跑的还是挺快的(最大的点1s多一点(USED O2))))
这线段树上有两个懒标记,分别是加法的和乘法的。。。。
嘛,你们看题解是不是不明白为什么叫先加再乘。。。
我也不明白。。。(再抄题解(没有复制))之后
我想明白了。。。。
你pushdown标记往下传的时候,你顺带把你的子儿子给更新一下
然后分别往这两个方向考虑
假如我们现在要对这个区间做乘法,直接把他的值跟新一下以及懒标记跟新一下
这时候不需要考虑之前加没加的情况,因为在这段区间当儿子的时候,之前加的已经算到这个区间里了
对区间做加法,同上
这时候不需要考虑之前乘没乘,因为这段区间当儿子的时候,之前乘的已经算进加法懒标记里了(就差到他的儿子去。。。。)
。。。。。
感性理解。。。
其实我觉得吧
你只要不像我一样,傻逼的把懒标记认为也维护当前点
应该这题可以随便过吧。。。。。(默写资料又增加了。。。。。)
#include<bits/stdc++.h>
#define MAXN 100005
typedef long long ll;
using namespace std;
ll n,m,mod,tp,x,y,k;
ll sum[MAXN * 4],l1[MAXN * 4],l2[MAXN * 4];//当前子树加和乘
void build(int rt , int l , int r){
l1[rt] = 1;
l2[rt] = 0;
if(l == r){cin>>sum[rt];return;}
int mid = (l + r) >> 1;
build(rt << 1 , l , mid);
build((rt << 1) | 1 , mid + 1 , r);
sum[rt] = (sum[rt << 1] + sum[(rt << 1) | 1]) % mod;
return;
}
void init(){
cin>>n>>m>>mod;
build(1 , 1 , n);
}
void push_down(int rt , int l , int r){
int mid = (r + l) >> 1;
sum[rt << 1] = sum[rt << 1] * l1[rt] + (mid - l + 1) * l2[rt];
sum[(rt << 1) | 1] = sum[(rt << 1) | 1] * l1[rt] + (r - mid) * l2[rt];
sum[rt << 1] %= mod;
sum[(rt << 1) | 1] %= mod;
l1[rt << 1] = (l1[rt << 1] * l1[rt]) % mod;
l1[(rt << 1) | 1] = (l1[(rt << 1) | 1] * l1[rt]) % mod;
l2[rt << 1] = (l2[rt << 1] * l1[rt] + l2[rt]) % mod;
l2[(rt << 1) | 1] = (l2[(rt << 1) | 1] * l1[rt] + l2[rt]) % mod;
l1[rt] = 1; l2[rt] = 0;
}
void add(int rt , int l , int r){//l----r乘k
if(y < l || r < x)return;
if(x <= l && r <= y){
sum[rt] = (sum[rt] * k) % mod;
l1[rt] = (l1[rt] * k) % mod;
l2[rt] = (l2[rt] * k) % mod;
return;
}
push_down(rt , l , r);
int mid = (l + r) >> 1;
add(rt << 1 , l , mid);
add((rt << 1) | 1 , mid + 1 , r);
sum[rt] = sum[rt << 1] + sum[(rt << 1) | 1];
sum[rt] %= mod;
}
void add2(int rt , int l , int r){//l---r加上k
if(y < l || r < x)return;
if(x <= l && r <= y){
sum[rt] = (sum[rt] + k * (r - l + 1)) % mod;
l2[rt] = (l2[rt] + k) % mod;
return;
}
push_down(rt , l , r);
int mid = (l + r) >> 1;
add2(rt << 1 , l , mid);
add2((rt << 1) | 1 , mid + 1 , r);
sum[rt] = sum[rt << 1] + sum[(rt << 1) | 1];
sum[rt] %= mod;
}
int que(int rt , int l , int r){
if(y < l || r < x)return 0;
if(x <= l && r <= y)return sum[rt];
push_down(rt , l , r);
int mid = (l + r) >> 1 , zz = 0;
zz = (zz + que(rt << 1 , l , mid)) % mod;
zz = (zz + que((rt << 1) | 1 , mid + 1 , r)) % mod;
return zz;
}
void solve(){
for(int i = 1 ; i <= m ; i++){
cin>>tp;
if(tp == 1){
cin>>x>>y>>k;
add(1 , 1 , n);
}
if(tp == 2){
cin>>x>>y>>k;
add2(1 , 1 , n);
}
if(tp == 3){
cin>>x>>y;
cout<<que(1 , 1 , n) % mod<<endl;
}
}
}
int main(){
init();
solve();
}