题目链接 题目链接 题目链接
线段树即将线性的数据构造成树型的结构,从而在 log 的时间范围内对区间的和进行查询,是一种用空间换时间的方法 线段树即将线性的数据构造成树型的结构,从而在\log的时间范围内对区间的和进行查询,是一种用空间换时间的方法 线段树即将线性的数据构造成树型的结构,从而在log的时间范围内对区间的和进行查询,是一种用空间换时间的方法
struct Node{ //l存储节点区间做坐标,r存储节点区间右坐标,ad存储加法操作,s存储区间和
int l,r,ad;
LL s;
}t[MAXN];
建树 建树 建树
void built_tree(int l,int root,int r){ //root当前节点编号,l当前节点的左边界,r当前节点的有边界
t[root].l = l; t[root].r = r; t[root].ad = 0;
if(l == r){ //l = r说明是叶节点
t[root].s = a[l];
return;
}
int mid = l + ((r - l) >> 1);
built_tree(l,root << 1,mid);
built_tree(mid + 1,(root << 1) | 1,r);
t[root].s = t[root << 1].s + t[(root << 1) | 1].s;
return;
}
加法下传
加法下传
加法下传
因为每次只对最高的区间进行操作,如果要调用下面的区间值,则需要将其父节点的加法下传,要注意每次调用子节点之前都要将父节点的加法下传
因为每次只对最高的区间进行操作,如果要调用下面的区间值,则需要将其父节点的加法下传,要注意每次调用子节点之前都要将父节点的加法下传
因为每次只对最高的区间进行操作,如果要调用下面的区间值,则需要将其父节点的加法下传,要注意每次调用子节点之前都要将父节点的加法下传
void pushdown(int root){
t[root << 1].s += (t[root << 1].r - t[root << 1] + 1) * t[root].ad;
t[(root << 1) | 1].s += (t[(root << 1) | 1].r - t[(root << 1) | 1].r + 1) * t[root].ad;
t[root << 1].ad += t[root].ad;
t[(root << 1) | 1].ad += t[root].ad;
t[root].ad = 0;
return;
}
区间加 区间加 区间加
void add_tree(int l,int root,int r,int k){
if(l > t[root].r || r < t[root].l) return;
if(l <= t[root].l && r >= t[root].r){
t[root].s += (t[root].r - t[root].l) * k;
t[root].ad += k;
}
pushdown(root);
int mid = l + ((r - l) >> 1);
add_tree(l,root << 1,mid,k);
add_tree(mid + 1,(root << 1) | 1,r,k);
t[root].s = t[root << 1].s + t[(root << 1) | 1].s;
}
区间查询 区间查询 区间查询
int inter_tree(int l,int root,int r){
if(l > t[root].r || r < t[root].l) return 0;
if(l <= t[root.l] && r >= t[root].r) return t[root].s;
pushdown(root);
return inter_tree(l,root << 1,r) + inter_tree(l,(root << 1) | 1,r);
}
乘法模板 乘法模板 乘法模板
void mul_tree(int l,int root,int r,int k){
if(l > t[root].r || r < t[root].l) return;
if(l <= t[root].l && r >= t[root].r){
t[root].s = t[root].s * k % p;
t[root].mul = t[root].mul * k % p;
t[root].ad = t[root].ad * k % p;
return;
}
int mid = t[root].l + ((t[root].r - t[root].l) >> 1);
pushdown(root);
mul_tree(l,root << 1,r,k);
mul_tree(l,(root << 1) | 1,r,k);
t[root].s = (t[root << 1].s + t[(root << 1) | 1].s) % p;
return;
}
加入乘法后在标记下传时要注意线下传乘法,让子节点的加法标记先乘,在下传加法 加入乘法后在标记下传时要注意线下传乘法,让子节点的加法标记先乘,在下传加法 加入乘法后在标记下传时要注意线下传乘法,让子节点的加法标记先乘,在下传加法
void pushdown(int root){
t[root << 1].s = (t[root << 1].s * t[root].mul % p + (t[root << 1].r - t[root << 1] + 1) * t[root].ad) % p;
t[root << 1].mul *= t[root].mul;
t[root << 1].ad = t[root << 1].ad * t[root].mul + t[root].ad;
t[(root << 1) | 1].s += (t[(root << 1) | 1].s * t[root].mul % p + (t[(root << 1) | 1].r - t[(root << 1) | 1].r + 1) * t[root].ad) % p;
t[(root << 1) | 1].mul *= t[root].mul;
t[(root << 1) | 1].ad = t[(root << 1) | 1].ad * t[root].mul + t[root].ad;
t[root].ad = 0;
t[root].mul = 1;
return;
}
下面附上两道题的
a
c
代码
下面附上两道题的ac代码
下面附上两道题的ac代码
加法
\tiny\mathbf{加法}
加法
#include<iostream>
#include<cstdio>
#include<cstring>
#define LL unsigned long long
using namespace std;
int n,m;
LL a[100005];
struct Node{
int l,r;
LL ad,s;
}t[500005];
LL read(){
char c = getchar();
int n = 0,l = 1;;
while(c < '0' || c > '9') {
if(c == '-') l = -1;
c = getchar();
}
while(c >= '0' && c <= '9'){
n = (n << 1) + (n << 3) + (c & 15);
c = getchar();
}
return n * l;
}
void pushdown(int root){
int l = t[root].l,r = t[root].r;
int mid = l + ((r - l) >> 1);
t[root << 1].s = t[root << 1].s + (mid - l + 1) * t[root].ad;
t[(root << 1) | 1].s = t[(root << 1) | 1].s + (r - mid) * t[root].ad;
t[root << 1].ad += t[root].ad;
t[(root << 1) | 1].ad += t[root].ad;
t[root].ad = 0;
return;
}
void built_tree(int l,int root,int r){
t[root].l = l; t[root].r = r; t[root].ad = 0;
if(l == r){
t[root].s = a[l];
return;
}
int mid = l + ((r - l) >> 1);
built_tree(l,root << 1,mid);
built_tree(mid + 1,(root << 1) | 1,r);
t[root].s = t[root << 1].s + t[(root << 1) | 1].s;
}
void add_tree(int l,int root,int r,int k){
if(l > t[root].r || r < t[root].l) return;
if(l <= t[root].l && r >= t[root].r){
t[root].s += (t[root].r - t[root].l + 1) * k;
t[root].ad += k;
return;
}
int mid = t[root].l + ((t[root].r - t[root].l) >> 1);
pushdown(root);
add_tree(l,root << 1,r,k);
add_tree(l,(root << 1) | 1,r, k);
t[root].s = t[root << 1].s + t[(root << 1) | 1].s;
return;
}
LL inter_tree(int l,int root,int r){
if(l > t[root].r || r < t[root].l) return 0;
if(l <= t[root].l && r >= t[root].r) return t[root].s;
pushdown(root);
int mid = t[root].l + ((t[root].r - t[root].l) >> 1);
return inter_tree(l,root << 1,r) + inter_tree(l,(root << 1) | 1,r);
}
int main(){
n = read(),m = read();
for(int i = 1; i <= n; i ++)
a[i] = read();
built_tree(1,1,n);
for(int i = 1; i <= m; i ++){
int f = read();
if(f == 1){
LL x = read(),y = read(),k = read();
add_tree(x,1,y,k);
}
if(f == 2){
LL x = read(),y = read();
printf("%lld\n",inter_tree(x,1,y));
}
}
return 0;
}
乘法 \tiny\mathbf{乘法} 乘法
#include<iostream>
#include<cstdio>
#include<cstring>
#define LL unsigned long long
using namespace std;
int n,m;
LL p;
LL a[100005];
struct Node{
int l,r;
LL ad,s,mul;
}t[500005];
LL read(){
char c = getchar();
int n = 0,l = 1;;
while(c < '0' || c > '9') {
if(c == '-') l = -1;
c = getchar();
}
while(c >= '0' && c <= '9'){
n = (n << 1) + (n << 3) + (c & 15);
c = getchar();
}
return n * l;
}
void pushdown(int root){
int l = t[root].l,r = t[root].r;
int mid = l + ((r - l) >> 1);
t[root << 1].s = (t[root << 1].s * t[root].mul % p+ (mid - l + 1) * t[root].ad % p) % p;
t[(root << 1) | 1].s = (t[(root << 1) | 1].s * t[root].mul % p + (r - mid) * t[root].ad % p) % p;
t[root << 1].ad = (t[root << 1].ad * t[root].mul % p + t[root].ad) % p;
t[root << 1]. mul = t[root << 1].mul * t[root].mul % p;
t[(root << 1) | 1].ad = ((t[(root << 1) | 1].ad * t[root].mul % p) + t[root].ad) % p;
t[(root << 1) | 1].mul = t[(root << 1) | 1].mul * t[root].mul % p;
t[root].ad = 0;
t[root].mul = 1;
return;
}
void built_tree(int l,int root,int r){
t[root].l = l; t[root].r = r; t[root].ad = 0; t[root].mul = 1;
if(l == r){
t[root].s = a[l] % p;
return;
}
int mid = l + ((r - l) >> 1);
built_tree(l,root << 1,mid);
built_tree(mid + 1,(root << 1) | 1,r);
t[root].s = (t[root << 1].s + t[(root << 1) | 1].s) % p;
return;
}
void add_tree(int l,int root,int r,int k){
if(l > t[root].r || r < t[root].l) return;
if(l <= t[root].l && r >= t[root].r){
t[root].s = (t[root].s + (t[root].r - t[root].l + 1) * k % p) % p;
t[root].ad = (t[root].ad + k) % p;
return;
}
pushdown(root);
add_tree(l,root << 1,r,k);
add_tree(l,(root << 1) | 1,r, k);
t[root].s = (t[root << 1].s + t[(root << 1) | 1].s) % p;
return;
}
void mul_tree(int l,int root,int r,int k){
if(l > t[root].r || r < t[root].l) return;
if(l <= t[root].l && r >= t[root].r){
t[root].s = t[root].s * k % p;
t[root].mul = t[root].mul * k % p;
t[root].ad = t[root].ad * k % p;
return;
}
int mid = t[root].l + ((t[root].r - t[root].l) >> 1);
pushdown(root);
mul_tree(l,root << 1,r,k);
mul_tree(l,(root << 1) | 1,r,k);
t[root].s = (t[root << 1].s + t[(root << 1) | 1].s) % p;
return;
}
LL inter_tree(int l,int root,int r){
if(l > t[root].r || r < t[root].l) return 0;
if(l <= t[root].l && r >= t[root].r) return t[root].s;
pushdown(root);
return (inter_tree(l,root << 1,r) + inter_tree(l,(root << 1) | 1,r)) % p;
}
int main(){
n = read(),m = read(),p = read();
for(int i = 1; i <= n; i ++)
a[i] = read();
built_tree(1,1,n);
for(int i = 1; i <= m; i ++){
int f = read();
if(f == 1){
LL x = read(),y = read(),k = read();
mul_tree(x,1,y,k);
}
if(f == 2){
LL x = read(),y = read(),k = read();
add_tree(x,1,y,k);
}
if(f == 3){
LL x = read(),y = read();
printf("%lld\n",inter_tree(x,1,y));
}
}
return 0;
}