玄学问题(玄关

学术版

HX_ztx @ 2024-11-28 19:11:10

在线段树中

void pushdown(int u,int l,int r){
    int m=(l+r)>>1;
    mark(u*2,l,m,lza[u],2);
    mark(u*2,l,m,lzm[u],1);
    mark(u*2+1,m+1,r,lza[u],2);
    mark(u*2+1,m+1,r,lzm[u],1);
    lzm[u]=1;
    lza[u]=0;
}

是错的

void pushdown(int u,int l,int r){
    int m=(l+r)>>1;
    mark(u*2,l,m,lzm[u],1);
    mark(u*2,l,m,lza[u],2);
    mark(u*2+1,m+1,r,lzm[u],1);
    mark(u*2+1,m+1,r,lza[u],2);
    lza[u]=0;
    lzm[u]=1;
}

是对的

为什么???

完整AC code

题目

#include<bits/stdc++.h>
using namespace std;
const int N=4e6+10;
#define int long long
int n,q,mod,x,y,k,a[N],opt;
int w[N],lzm[N],lza[N];
void pushup(int u){
    w[u]=(w[u*2]+w[u*2+1])%mod;
}
void build(int u,int l,int r){
    if(l==r){
        w[u]=a[l];
        return ;
    }
    lzm[u]=1;
    int m=(l+r)>>1;
    build(u*2,l,m);
    build(u*2+1,m+1,r);
    pushup(u);
}
bool in(int l,int r,int x,int y){
    return (x<=l)&&(y>=r);
}
bool out(int l,int r,int x,int y){
    return (x>r)||(y<l);
}
void mark(int u,int l,int r,int p,int op){
    if(op==1){
        (lzm[u]*=p)%=mod;
        (lza[u]*=p)%=mod;
        (w[u]*=p)%=mod;
    }
    else {
        (lza[u]+=p)%=mod;
        (w[u]+=(r-l+1)*p)%=mod;
    }
}
void pushdown(int u,int l,int r){
    int m=(l+r)>>1;
    mark(u*2,l,m,lzm[u],1);
    mark(u*2,l,m,lza[u],2);
    mark(u*2+1,m+1,r,lzm[u],1);
    mark(u*2+1,m+1,r,lza[u],2);
    lza[u]=0;
    lzm[u]=1;
}
int query(int u,int l,int r,int x,int y){
    if(in(l,r,x,y)){
        return w[u];
    }
    else if(!out(l,r,x,y)){
        int m=(l+r)>>1;
        pushdown(u,l,r);
        return (query(u*2,l,m,x,y)%mod+query(u*2+1,m+1,r,x,y)%mod)%mod;
    }
    else return 0;
}
void update(int u,int l,int r,int x,int y,int p,int op){
    if(in(l,r,x,y)){
        mark(u,l,r,p,op);
    }
    else if(!out(l,r,x,y)){
        int m=(l+r)>>1;
        pushdown(u,l,r);
        update(u*2,l,m,x,y,p,op);
        update(u*2+1,m+1,r,x,y,p,op);
        pushup(u);
    }
}
signed main(){
    ios::sync_with_stdio(false);
    cin.tie(0);cout.tie(0);
    cin>>n>>q>>mod;
    for(int i=1;i<=n;i++){
        cin>>a[i];
    }
    build(1,1,n);
    while(q--){
        cin>>opt;
        if(opt==1){
            cin>>x>>y>>k;
            update(1,1,n,x,y,k,1);
        }
        else if(opt==2){
            cin>>x>>y>>k;
            update(1,1,n,x,y,k,2);
        }
        else {
            cin>>x>>y;
            cout<<query(1,1,n,x,y)<<endl;
        }
    }
    return 0;
}

by csb0118 @ 2024-11-28 19:31:24

我认为,lzm和lza的作用应该是把区间表示为 w_父 * lzm+lza,是先算 lzm 再算 + lza 的。如果把“mark(u 2,l,m,lza[u],2);”和“mark(u2+1,m+1,r,lza[u],2);”放在前面,子区间就变成了先 +lza 再 lzm,展开后就变成了 “w_子 * lzm +(lza * lzm)”(w_子包含原有的懒标记),但正确的应该是w_子 * lzm +lza


by csb0118 @ 2024-11-28 19:32:49

我也是蒟蒻,我也不太懂(逃


by HX_ztx @ 2024-11-28 19:34:36

@csb0118先谢谢,关了,让我这个蒟蒻思考一下


by HX_ztx @ 2024-11-28 19:37:24

@csb0118哦哦哦懂了,就是这样,谢谢啦


by csb0118 @ 2024-11-28 19:44:36

@HX_ztx别客气,我也相当于是重新理清了一下思路。


by int_4096 @ 2024-11-28 19:56:18

@HX_ztx 这个我熟悉。
关键问题在于你的 tag 是先加再乘还是先乘再加。 此处应是先乘再加。

还有,推荐一种写法,tag 写在一起。
可以有效避免:

  1. 用标记更新区间(你的 mark,我的 update) 也不用写一堆。
  2. tag 合并也方便一些,不用每个挨个合并。
  3. 同时推荐左右儿子写成 lsrs
    struct TAG {
    ll mul, add;
    TAG() {}
    TAG(ll mul, ll add) : mul(mul), add(add) {}
    TAG& operator+=(const TAG& rhs) {
        mul = (mul * rhs.mul) % mod;
        add = (add * rhs.mul + rhs.add) % mod;
        return *this;
    }
    } tag[N << 2];
    void update(int u, int s, int t, TAG T) {
    sum[u] = (sum[u] * T.mul + T.add * (t - s + 1)) % mod;
    tag[u] += T;
    }
    void pushdown(int u, int s, int t) {
    int mid = (s + t) >> 1;
    update(ls(u), s, mid, tag[u]);
    update(rs(u), mid + 1, t, tag[u]);
    tag[u] = Empty;
    }
    void modify(int u, int l, int r, int s, int t, TAG v) {
    if (l <= s && r >= t)
        return update(u, s, t, v);
    int mid = (s + t) >> 1;
    pushdown(u, s, t);
    if (l <= mid)
        modify(ls(u), l, r, s, mid, v);
    if (r > mid)
        modify(rs(u), l, r, mid + 1, t, v);
    maintain(u);
    }

    自认为还是十分清爽的。


by HX_ztx @ 2024-11-28 20:23:02

@int_4096,先谢谢了,但是蒟蒻没时间学了,这次noip之后就AFO


by HX_ztx @ 2024-11-28 20:25:58

@int_4096我会传给机房下一代的!!


by int_4096 @ 2024-11-29 08:15:46

@HX_ztx 好的!

不知道为什么很多人的线段树写的很不可读(


|