线段树~
这(D)道(Q)题(S)告诉我说:“你没学过线段树”
嗯……
这题要好好想想……QAQ
来吧
首先要明确的事情是
delta[now]记录的是已经对当前点做过的,但是还没有对当前点的儿子做过的操作
嗯……
我们就这样
慢慢的退一下
嗯
标记是给儿子用的
嗯
是给儿子用的
奉献精神
然后,对于这个题,我们可以把所有操作统一为对该节点*x
+y
的形式
void change(int l,int r,LL add,LL mult,int p)
那么区间乘就成了change(l,r,0,v,1);
那么区间加就成了change(l,r,v,1,1);
标记是什么?
对目前的答案进行标记该有的操作之后会得到真实的答案
真理往往隐蔽在众多表象的茫茫迷雾之中,而标记就像穿透这迷雾的明灯,引导着探索者到达真理的彼岸
(old_ans * mult) + add = new_old
标记的作用是引导儿子走上正轨
所以说下放标记的时候要将儿子的ans计算出来
嗯
然后怎么更新标记
这成了大问题
设
{
a = mult
b = add
change(l,r,d,c,1)
x = 更新之后的mult
y = 更新之后的add
}
为了使得
(sum * a + b) * c + d == sum * x + y
sum * a * c + b * c + d == sum * x + y
x = a * c
y = b * c + d
然后就可以更新了~
嗯
kill
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
#define L(x) (x << 1)
#define R(x) (x << 1 | 1)
#define sz(x) (tree[x].r - tree[x].l + 1)
using namespace std;
const int MAXN = 100000 + 5;
typedef long long LL;
int P;
struct dot
{
int l,r;
LL sum,add,mult;
}tree[MAXN << 2];
int num[MAXN];
void update(int p)
{
tree[p].sum = (tree[L(p)].sum + tree[R(p)].sum) % P;
return;
}
void build(int l,int r,int p)
{
tree[p].l = l;
tree[p].r = r;
tree[p].mult = 1;
if(l == r)
{
tree[p].sum = num[l];
return;
}
int mid = (l + r) >> 1;
build(l,mid,L(p));
build(mid + 1,r,R(p));
update(p);
return;
}
void spread(int p)
{
tree[L(p)].mult = (tree[L(p)].mult * tree[p].mult) % P;
tree[L(p)].add = ((tree[L(p)].add * tree[p].mult) % P + tree[p].add % P) % P;
tree[L(p)].sum = ((tree[L(p)].sum * tree[p].mult) % P + (tree[p].add * sz(L(p))) % P) % P;
tree[R(p)].mult = (tree[R(p)].mult * tree[p].mult) % P;
tree[R(p)].add = ((tree[R(p)].add * tree[p].mult) % P + tree[p].add % P) % P;
tree[R(p)].sum = ((tree[R(p)].sum * tree[p].mult) % P + (tree[p].add * sz(R(p))) % P) % P;
tree[p].add = 0;
tree[p].mult = 1;
return;
}
void change(int l,int r,LL add,LL mult,int p)
{
if(l <= tree[p].l && tree[p].r <= r)
{
tree[p].mult = (tree[p].mult * mult) % P;
tree[p].add = ((tree[p].add * mult) % P + add % P) % P;
tree[p].sum = ((tree[p].sum * mult) % P + (add * sz(p)) % P) % P;
return;
}
spread(p);
int mid = (tree[p].l + tree[p].r) >> 1;
if(l <= mid)change(l,r,add,mult,L(p));
if(mid < r)change(l,r,add,mult,R(p));
update(p);
return;
}
LL ask(int l,int r,int p)
{
if(l <= tree[p].l && tree[p].r <= r)
return tree[p].sum;
spread(p);
LL ans = 0;
int mid = (tree[p].l + tree[p].r) >> 1;
if(l <= mid)ans += ask(l,r,L(p));
if(mid < r)ans += ask(l,r,R(p));
return ans;
}
int n,m;
int q,a,b;
LL v;
int main()
{
scanf("%d %lld",&n,&P);
for(int i = 1;i <= n;i ++)
scanf("%d",&num[i]);
build(1,n,1);
scanf("%d",&m);
for(int i = 1;i <= m;i ++)
{
scanf("%d",&q);
switch(q)
{
case 1:scanf("%d %d %lld",&a,&b,&v);change(a,b,0ll,v,1);break;
case 2:scanf("%d %d %lld",&a,&b,&v);change(a,b,v,1ll,1);break;
case 3:scanf("%d %d",&a,&b);printf("%lld\n",ask(a,b,1) % P);break;
}
}
return 0;
}