【线段树】各种模板集合
这里放蒟蒻 lrj124 碰到的线段树区间操作集合
No.1 区间加
懒标记
/************************************************
*Author : lrj124
*Created Time : 2019.04.04.14:17
*Mail : 1584634848@qq.com
*Problem : seg
************************************************/
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn = 100000 + 10;
int n,m;
struct seg { int l,r; ll mark,sum; } tree[maxn<<2];
inline void pushup(int root) { tree[root].sum = tree[root<<1].sum+tree[root<<1|1].sum; }
inline void pushdown(int root) {
if (tree[root].mark) {
tree[root<<1].mark += tree[root].mark;
tree[root<<1|1].mark += tree[root].mark;
tree[root<<1].sum += tree[root].mark*(tree[root<<1].r-tree[root<<1].l+1);
tree[root<<1|1].sum += tree[root].mark*(tree[root<<1|1].r-tree[root<<1|1].l+1);
tree[root].mark = 0;
}
}
inline void Build(int l,int r,int root) {
tree[root].l = l;
tree[root].r = r;
if (l == r) {
scanf("%lld",&tree[root].sum);
return;
}
int mid = l+r>>1;
Build(l,mid,root<<1);
Build(mid+1,r,root<<1|1);
pushup(root);
}
inline void update(int l,int r,int ql,int qr,int root,ll x) {
if (qr < l || ql > r) return;
if (ql <= l && r <= qr) {
tree[root].mark += x;
tree[root].sum += x*(r-l+1);
return;
}
pushdown(root);
int mid = l+r>>1;
update(l,mid,ql,qr,root<<1,x);
update(mid+1,r,ql,qr,root<<1|1,x);
pushup(root);
}
inline ll query(int l,int r,int ql,int qr,int root) {
if (qr < l || ql > r) return 0;
if (ql <= l && r <= qr) return tree[root].sum;
pushdown(root);
int mid = l+r>>1;
return query(l,mid,ql,qr,root<<1)+query(mid+1,r,ql,qr,root<<1|1);
}
int main() {
//freopen("seg.in","r",stdin);
//freopen("seg.out","w",stdout);
scanf("%d%d",&n,&m);
Build(1,n,1);
while (m--) {
int op,x,y;
ll k;
scanf("%d%d%d",&op,&x,&y);
if (op == 1) {
scanf("%lld",&k);
update(1,n,x,y,1,k);
} else printf("%lld\n",query(1,n,x,y,1));
}
return 0;
}
No.2 区间加,区间乘
加个乘法标记
#include <cstdio>
const int maxn = 100000 + 10;
struct Seg { long long l,r,sum,add,mul; } tree[maxn*4];
long long p;
long long n,m;
inline void pushup(long long root) { tree[root].sum = tree[root<<1].sum+tree[root<<1|1].sum; tree[root].sum %= p; }
inline void BuildTree(long long l,long long r,long long root) {
tree[root].l = l;
tree[root].r = r;
tree[root].mul = 1;
if (l == r) {
scanf("%lld",&tree[root].sum);
tree[root].sum %= p;
return;
}
long long mid = l+r>>1;
BuildTree(l,mid,root<<1);
BuildTree(mid+1,r,root<<1|1);
pushup(root);
}
inline void pushdown(long long root) {
if (tree[root].mul != 1) {
tree[root<<1].mul = tree[root<<1].mul*tree[root].mul%p;
tree[root<<1|1].mul = tree[root<<1|1].mul*tree[root].mul%p;
tree[root<<1].add = tree[root<<1].add*tree[root].mul%p;
tree[root<<1|1].add = tree[root<<1|1].add*tree[root].mul%p;
tree[root<<1].sum = tree[root<<1].sum*tree[root].mul%p;
tree[root<<1|1].sum = tree[root<<1|1].sum*tree[root].mul%p;
tree[root].mul = 1;
}
if (tree[root].add != 0) {
tree[root<<1].add = (tree[root<<1].add+tree[root].add)%p;
tree[root<<1|1].add = (tree[root<<1|1].add+tree[root].add)%p;
tree[root<<1].sum = (tree[root<<1].sum+tree[root].add*(tree[root<<1].r-tree[root<<1].l+1))%p;
tree[root<<1|1].sum = (tree[root<<1|1].sum+tree[root].add*(tree[root<<1|1].r-tree[root<<1|1].l+1))%p;
tree[root].add = 0;
}
}
inline void UpdateAdd(long long ql,long long qr,long long l,long long r,long long root,long long x) {
if (ql > r || qr < l) return;
if (ql <= l && qr >= r) {
tree[root].add = (tree[root].add+x)%p;
tree[root].sum = (tree[root].sum+x*(r-l+1))%p;
return;
}
pushdown(root);
long long mid = l+r>>1;
UpdateAdd(ql,qr,l,mid,root<<1,x);
UpdateAdd(ql,qr,mid+1,r,root<<1|1,x);
pushup(root);
}
inline void UpdateMul(long long ql,long long qr,long long l,long long r,long long root,long long x) {
if (ql > r || qr < l) return;
if (ql <= l && qr >= r) {
tree[root].add = tree[root].add*x%p;
tree[root].mul = tree[root].mul*x%p;
tree[root].sum = tree[root].sum*x%p;
return;
}
pushdown(root);
long long mid = l+r>>1;
UpdateMul(ql,qr,l,mid,root<<1,x);
UpdateMul(ql,qr,mid+1,r,root<<1|1,x);
pushup(root);
}
inline long long Query(long long ql,long long qr,long long l,long long r,long long root) {
if (ql > r || qr < l) return 0;
if (ql <= l && qr >= r) return tree[root].sum;
pushdown(root);
long long mid = l+r>>1;
return (Query(ql,qr,l,mid,root<<1)+Query(ql,qr,mid+1,r,root<<1|1))%p;
}
int main() {
scanf("%lld%lld%lld",&n,&m,&p);
BuildTree(1,n,1);
while (m--) {
long long val;
long long op,l,r;
scanf("%lld%lld%lld",&op,&l,&r);
if (op == 1) {
scanf("%lld",&val);
UpdateMul(l,r,1,n,1,val);
} else if (op == 2) {
scanf("%lld",&val);
UpdateAdd(l,r,1,n,1,val);
} else printf("%lld\n",Query(l,r,1,n,1));
}
return 0;
}
No.3 把区间中等于 \(x\) 的数改成 \(y\)
对每个数开一个 tag,表示每个数会映射到哪个数。
/************************************************
*Author : lrj124
*Created Time : 2019.10.04.14:07
*Mail : 1584634848@qq.com
*Problem : cf911g
************************************************/
#include <cstdio>
const int maxn = 200000 + 10;
int n,q,a[maxn],tag[maxn<<2][101];
inline void pushdown(int root) {
for (int i = 1;i <= 100;i++) {
tag[root<<1][i] = tag[root][tag[root<<1][i]];
tag[root<<1|1][i] = tag[root][tag[root<<1|1][i]];
}
for (int i = 1;i <= 100;i++) tag[root][i] = i;
}
inline void update(int l,int r,int ul,int ur,int num,int root,int x) {
if (l > ur || r < ul) return;
if (ul <= l && r <= ur) {
for (int i = 1;i <= 100;i++)
if (tag[root][i] == num) tag[root][i] = x;
return;
}
pushdown(root);
int mid = l+r>>1;
update(l,mid,ul,ur,num,root<<1,x);
update(mid+1,r,ul,ur,num,root<<1|1,x);
}
inline void print(int l,int r,int root) {
if (l == r) {
printf("%d ",tag[root][a[l]]);
return;
}
pushdown(root);
int mid = l+r>>1;
print(l,mid,root<<1);
print(mid+1,r,root<<1|1);
}
int main() {
// freopen("cf911g.in","r",stdin);
// freopen("cf911g.out","w",stdout);
scanf("%d",&n);
for (int i = 1;i <= n;i++) scanf("%d",&a[i]);
for (int i = 1;i <= n<<2;i++) for (int j = 1;j <= 100;j++) tag[i][j] = j;
for (scanf("%d",&q);q--;) {
int l,r,x,y;
scanf("%d%d%d%d",&l,&r,&x,&y);
update(1,n,l,r,x,1,y);
}
print(1,n,1);
return 0;
}
No.4 区间每个数开方
就是暴力递归到每个叶子节点,若当前区间 Max 小于 2 就 return
/************************************************
*Author : lrj124
*Created Time : 2019.09.28.14:24
*Mail : 1584634848@qq.com
*Problem : luogu4145
************************************************/
#include <algorithm>
#include <cstdio>
#include <cmath>
using ll = long long;
const int maxn = 100000 + 10;
ll sum[maxn<<2],maxv[maxn<<2];
inline void pushup(int root) {
sum[root] = sum[root<<1]+sum[root<<1|1];
maxv[root] = std :: max(maxv[root<<1],maxv[root<<1|1]);
}
inline void build(int l,int r,int root) {
if (l == r) {
scanf("%lld",&sum[root]);
maxv[root] = sum[root];
return;
}
int mid = l+r>>1;
build(l,mid,root<<1);
build(mid+1,r,root<<1|1);
pushup(root);
}
inline void update(int l,int r,int ul,int ur,int root) {
if (l > ur || r < ul || maxv[root] < 2) return;
if (l == r) {
maxv[root] = sum[root] = sqrt(sum[root]);
return;
}
int mid = l+r>>1;
update(l,mid,ul,ur,root<<1);
update(mid+1,r,ul,ur,root<<1|1);
pushup(root);
}
inline ll query(int l,int r,int ql,int qr,int root) {
if (l > qr || r < ql) return 0;
if (ql <= l && r <= qr) return sum[root];
int mid = l+r>>1;
return query(l,mid,ql,qr,root<<1)+query(mid+1,r,ql,qr,root<<1|1);
}
int main() {
for (int n,q,x,y,z;scanf("%d",&n) ^ EOF;puts("")) {
build(1,n,1);
for (scanf("%d",&q);q--;) {
scanf("%d%d%d",&x,&y,&z);
if (y > z) std :: swap(y,z);
if (x) printf("%lld\n",query(1,n,y,z,1));
else update(1,n,y,z,1);
}
}
return 0;
}
No.5 区间取 Min,Max
把 pushup 改一改就行,
区间和 \(x\) 取 Max 时,区间最大和区间最小都和 \(x\) 取 Max
区间和 \(x\) 取 Min 时,区间最大和区间最小都和 \(x\) 取 Min
/************************************************
*Author : lrj124
*Created Time : 2019.10.03.21:38
*Mail : 1584634848@qq.com
*Problem : luogu4560
************************************************/
#include <algorithm>
#include <cstdio>
using namespace std;
const int maxn = 2000000 + 10;
int n,q,maxv[maxn<<2],minv[maxn<<2];
inline void pushup_max(int root,int x) {
minv[root] = max(minv[root],x);
maxv[root] = max(maxv[root],x);
}
inline void pushup_min(int root,int x) {
minv[root] = min(minv[root],x);
maxv[root] = min(maxv[root],x);
}
inline void pushdown(int root) {
pushup_max(root<<1,maxv[root]);
pushup_max(root<<1|1,maxv[root]);
pushup_min(root<<1,minv[root]);
pushup_min(root<<1|1,minv[root]);
maxv[root] = 0; minv[root] = 999999;
}
inline void take_max(int l,int r,int ul,int ur,int root,int x) {
if (l > ur || r < ul) return;
if (ul <= l && r <= ur) {
pushup_max(root,x);
return;
}
pushdown(root);
int mid = l+r>>1;
take_max(l,mid,ul,ur,root<<1,x);
take_max(mid+1,r,ul,ur,root<<1|1,x);
}
inline void take_min(int l,int r,int ul,int ur,int root,int x) {
if (l > ur || r < ul) return;
if (ul <= l && r <= ur) {
pushup_min(root,x);
return;
}
pushdown(root);
int mid = l+r>>1;
take_min(l,mid,ul,ur,root<<1,x);
take_min(mid+1,r,ul,ur,root<<1|1,x);
}
inline void print(int l,int r,int root) {
if (l == r) {
printf("%d\n",maxv[root]);
return;
}
pushdown(root);
int mid = l+r>>1;
print(l,mid,root<<1);
print(mid+1,r,root<<1|1);
}
int main() {
for (scanf("%d%d",&n,&q);q--;) {
int op,l,r,w;
scanf("%d%d%d%d",&op,&l,&r,&w);
if (op == 1) take_max(1,n,l+1,r+1,1,w);
else take_min(1,n,l+1,r+1,1,w);
}
print(1,n,1);
return 0;
}
No.6 单点修改,区间询问最大连续子段和
只需要维护四个数:
max
,lmax
,rmax
,sum
分别表示区间最大连续子段和,区间左缀最大连续和,区间右缀最大连续和,区间和
lmax = max(lmax,rson.sum+rson.lmax)
rmax = max(rmax,lson.sum+lson.rmax)
max = max(lson.max,rson.max,lson.rmax+rson.lmax)
代码
/************************************************
*Author : lrj124
*Created Time : 2019.09.15.08:38
*Mail : 1584634848@qq.com
*Problem : spoj1716
************************************************/
#include <algorithm>
#include <cstdio>
using namespace std;
const int maxn = 50000 + 10;
struct seg { int l,r,sum,max; } tree[maxn<<2];
int n,q;
inline void pushup(int root) {
tree[root].sum = tree[root<<1].sum+tree[root<<1|1].sum;
tree[root].l = max(tree[root<<1].l,tree[root<<1|1].l+tree[root<<1].sum);
tree[root].r = max(tree[root<<1|1].r,tree[root<<1].r+tree[root<<1|1].sum);
tree[root].max = max(tree[root<<1].r+tree[root<<1|1].l,max(tree[root<<1].max,tree[root<<1|1].max));
}
inline void build(int l,int r,int root) {
if (l == r) {
int x; scanf("%d",&x);
tree[root] = { x,x,x,x };
return;
}
int mid = l+r>>1;
build(l,mid,root<<1);
build(mid+1,r,root<<1|1);
pushup(root);
}
inline void update(int l,int r,int num,int root,int x) {
if (l > num || r < num) return;
if (l == r) {
tree[root] = { x,x,x,x };
return;
}
int mid = l+r>>1;
update(l,mid,num,root<<1,x);
update(mid+1,r,num,root<<1|1,x);
pushup(root);
}
inline seg query(int l,int r,int ql,int qr,int root) {
if (ql <= l && r <= qr) return tree[root];
int mid = l+r>>1;
if (mid >= qr) return query(l,mid,ql,qr,root<<1);
if (ql > mid) return query(mid+1,r,ql,qr,root<<1|1);
seg lson = query(l,mid,ql,qr,root<<1),rson = query(mid+1,r,ql,qr,root<<1|1),ans;
ans = { max(lson.l,rson.l+lson.sum),max(rson.r,lson.r+rson.sum),rson.sum+lson.sum,max(lson.r+rson.l,max(lson.max,rson.max)) };
return ans;
}
int main() {
// freopen("spoj1716.in","r",stdin);
// freopen("spoj1716.out","w",stdout);
scanf("%d",&n);
build(1,n,1);
for (scanf("%d",&q);q--;) {
int x,y,z; scanf("%d%d%d",&x,&y,&z);
if (x == 0) update(1,n,y,1,z);
else printf("%d\n",query(1,n,y,z,1).max);
}
return 0;
}