【BZOJ 1798】维护序列

来源:互联网 发布:淘宝达人直播哪里打开 编辑:程序博客网 时间:2024/06/05 19:32

线段树~
这(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;}
0 0
原创粉丝点击