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的作用应该是把区间表示为
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
写在一起。
可以有效避免:
mark
,我的 update
) 也不用写一堆。tag
合并也方便一些,不用每个挨个合并。ls
,rs
。
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 好的!
不知道为什么很多人的线段树写的很不可读(