P3373 【模板】线段树 2
内容有些肤浅,以后会深入证明,先挖好坑
题目链接
思路
这题乍一看觉得好难啊,然后我们来仔细分析一下题目
题目说有两种修改操作
1.区间加某一值
2.区间乘某一值
首先想到的思路一定是打两个\(lazymark\)
男就男在这两个操作有先后,我\(ri\),那么我们就应该来仔细看一下先后顺序对程序的影响
顺序无非就是两种:
1.先乘后加
先乘后加和数学一样,所以我们来先看一下这种
$tree[ls].date=(tree[ls].date\times tree[x].cheng\ %\ p+tree[x].jia\times (r-l+1)\ %\ p)\ %\ p \(
如此看来我们改变\)cheng\(的值时,只需要把\)jia\(去乘一下\)cheng$就行了
这样来看好像很对.........其实就是很对
2.先加后乘
那么我们来看一下这个
$tree[ls].date=(tree[ls].date+ tree[x].jia)\cdot tree[root].cheng\ %\ p \(
这样子的化就没法向上面的代码一样更新\)cheng\(时去维护\)jia$了
看完这里就没什么难的了,就是要写两个\(update\)去分别维护\(cheng,jia\)两个\(lazymark\)
上面的代码显示不全,就放张图吧
口胡
来详细解释(口胡)一波:
以下解释不针对题目只是口胡一波
现在我们要对区间\([l,r]\)进行一坨的加和乘的操作
先把它看成加法优先的情况
\((sum+lazy_{jia}) \times lazy_{cheng}\)
很容易看出来
如果我更新了$ lazy_{cheng}\(那么\)lazy_{jia}$也要改变所以我们变形一下
\((sum \times lazy_{cheng})+lazy_{jia}*lazy_{cheng}\)
设\(sjpnb=lazy_{jia}*lazy_{cheng}\)
那么就变成了;
\((sum \times lazy_{cheng})+sjpnb\)
如此来看\(lazy_{cheng}\)改变就不会导致\(lazy_{jia}\)变了
我们把\(sjpnb\)看成\(lazy_{jia}\)不就ok了?
口胡完成有什么错误请见谅,毕竟人家是菜鸡吗
代码
代码写的可能复杂了些,\(putdown\)函数写的有点复杂了,其实没必要像我这样写
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cmath>
#include<queue>
#include<stack>
#include<vector>
#include<map>
#include<string>
#include<cstring>
#define int long long int
#define lowbit(x) x & -x
const int N=100000;
using namespace std;
inline int read() {
char c = getchar();
int x = 0, f = 1;
while(c < '0' || c > '9') {
if(c == '-') f = -1;
c = getchar();
}
while(c >= '0' && c <= '9') x = x * 10 + c - '0', c = getchar();
return x * f;
}
int n,m,p,a[N*4];
struct node {
int date;
int cheng;
int jia;
} tree[N*4+10];
void pushup(int root) {
tree[root].date=(tree[root<<1].date+tree[root<<1|1].date)%p;
}
void build(int root,int l,int r) {
tree[root].cheng=1;
if(l==r) {
tree[root].date=a[l];
return ;
}
int mid=(l+r)/2;
build(root<<1,l,mid);
build(root<<1|1,mid+1,r);
pushup(root);
}
void pushdown(int x,int l,int r) {
int ls=x<<1,rs=x<<1|1,mid=(l+r)>>1;
tree[ls].date=(tree[ls].date*tree[x].cheng%p+tree[x].jia*(mid-l+1)%p)%p;
tree[ls].cheng=(tree[ls].cheng*tree[x].cheng)%p;
tree[ls].jia=(tree[ls].jia*tree[x].cheng+tree[x].jia)%p;
tree[rs].date=(tree[rs].date*tree[x].cheng%p+tree[x].jia*(r-(mid+1)+1)%p)%p;
tree[rs].cheng=(tree[rs].cheng*tree[x].cheng)%p;
tree[rs].jia=(tree[rs].jia*tree[x].cheng+tree[x].jia)%p;
tree[x].jia=0;
tree[x].cheng=1;
return;
}
void update_cheng(int root,int l,int r,int x,int y,int k) {
if(r<x || l>y) return ;
if(l>=x & r<=y) {
tree[root].date=(tree[root].date*k)%p;
tree[root].cheng=(tree[root].cheng*k)%p;
tree[root].jia=(tree[root].jia*k)%p;
return;
}
pushdown(root,l,r);
int mid=(l+r)>>1;
update_cheng(root<<1,l,mid,x,y,k);
update_cheng(root<<1|1,mid+1,r,x,y,k);
pushup(root);
}
void update_jia(int root,int l,int r,int x,int y,int k) {
if(r<x || l>y) return ;
if(l>=x & r<=y) {
tree[root].date=(tree[root].date+k*(r-l+1)%p)%p;
tree[root].jia=(tree[root].jia+k)%p;
return;
}
pushdown(root,l,r);
int mid=(l+r)>>1;
update_jia(root<<1,l,mid,x,y,k);
update_jia(root<<1|1,mid+1,r,x,y,k);
pushup(root);
}
int query(int root,int l,int r,int x,int y) {
if(r<x || l>y) return 0;
if(l>=x && r<=y) {
return tree[root].date;
}
pushdown(root,l,r);
int mid=(l+r)>>1;
return (query(root<<1,l,mid,x,y)+query(root<<1|1,mid+1,r,x,y))%p;
}
signed main() {
scanf("%lld %lld %lld",&n,&m,&p);
for(int i=1; i<=4*n; i++) tree[i].cheng=1;
for(int i=1; i<=n; i++) {
scanf("%lld",&a[i]);
}
build(1,1,n);
int opt,x,y,k;
while(m--) {
scanf("%lld",&opt);
if(opt==1) {
scanf("%lld %lld %lld",&x,&y,&k);
update_cheng(1,1,n,x,y,k);
}
if(opt==2) {
scanf("%lld %lld %lld",&x,&y,&k);
update_jia(1,1,n,x,y,k);
}
if(opt==3) {
scanf("%lld %lld",&x,&y);
cout<<query(1,1,n,x,y)%p<<endl;
}
}
return 0;
}