一、建树、区间加、区间查询和
P3372 【模板】线段树 1
#include <bits/stdc++.h>
using namespace std;
int n, m, a[100010], opt, x, y, k;
struct SegmentTree
{
int l, r;
long long sum, lazy;
}t[400010];
//建树 build(1, 1, n);
void build(int p, int l, int r)
{
t[p].l=l;
t[p].r=r;
if(l==r){
t[p].sum=a[l];
return;
}
int mid=(l+r)/2;
build(p*2, l, mid);
build(p*2+1, mid+1, r);
t[p].sum=t[p*2].sum+t[p*2+1].sum;
}
void spread(int p)
{
if(t[p].lazy){
t[p*2].sum+=t[p].lazy*(t[p*2].r-t[p*2].l+1);
t[p*2+1].sum+=t[p].lazy*(t[p*2+1].r-t[p*2+1].l+1);
t[p*2].lazy+=t[p].lazy;
t[p*2+1].lazy+=t[p].lazy;
t[p].lazy=0;
}
}
void change(int p, int l, int r, int d)
{
if(l<=t[p].l && r>=t[p].r){
t[p].sum+=d*(t[p].r-t[p].l+1);
t[p].lazy+=d;
return;
}
spread(p);
int mid=(t[p].l+t[p].r)/2;
if(l<=mid){
change(p*2, l, r, d);
}
if(r>mid){
change(p*2+1, l, r, d);
}
t[p].sum=t[p*2].sum+t[p*2+1].sum;
}
//区间查询 asd(1, l, r);
long long ask(int p, int l, int r)
{
if(l<=t[p].l && r>=t[p].r){ //完全覆盖
return t[p].sum;
}
spread(p); //下传延迟标记
int mid=(t[p].l+t[p].r)/2;
long long ans=0;
if(l<=mid){ //和左子节点有重叠
ans+=ask(p*2, l, r);
}
if(r>mid){ //和右子节点有重叠
ans+=ask(p*2+1, l, r);
}
return ans;
}
int main()
{
scanf("%d %d", &n, &m);
for(int i=1; i<=n; ++i){
scanf("%d", &a[i]);
}
build(1, 1, n);
while(m--){
scanf("%d", &opt);
if(opt==1){
scanf("%d %d %d", &x, &y, &k);
change(1, x, y, k);
}
else if(opt==2){
scanf("%d %d", &x, &y);
printf("%lld\n", ask(1, x, y));
}
}
return 0;
}
二、建树、单点修改、区间求和(不需要lazy tag)
P3374 【模板】树状数组 1
#include <bits/stdc++.h>
using namespace std;
int n, m, a[500010], opt;
struct SegmentTree
{
int l, r;
long long sum;
}t[2000010];
void build(int p, int l, int r)
{
t[p].l=l;
t[p].r=r;
if(l==r){
t[p].sum=a[l];
return;
}
int mid=(l+r)>>1;
build(p*2, l, mid);
build(p*2+1, mid+1, r);
t[p].sum=t[p*2].sum+t[p*2+1].sum;
}
void change(int p, int x, int v)
{
if(t[p].l==t[p].r){
t[p].sum+=v;
return;
}
int mid=(t[p].l+t[p].r)>>1;
if(x<=mid){
change(p*2, x, v);
}
else{
change(p*2+1, x, v);
}
t[p].sum=t[p*2].sum+t[p*2+1].sum;
}
long long ask(int p, int l, int r)
{
if(l<=t[p].l && r>=t[p].r){
return t[p].sum;
}
int mid=(t[p].l+t[p].r)>>1;
long long ans=0;
if(l<=mid){
ans+=ask(p*2, l, r);
}
if(r>mid){
ans+=ask(p*2+1, l, r);
}
return ans;
}
int main()
{
scanf("%d %d", &n, &m);
for(int i=1; i<=n; ++i){
scanf("%d", &a[i]);
}
build(1, 1, n);
while(m--){
int x, y, k;
scanf("%d", &opt);
if(opt==1){
scanf("%d %d", &x, &k);
change(1, x, k);
}
else if(opt==2){
scanf("%d %d", &x, &y);
printf("%lld\n", ask(1, x, y));
}
}
return 0;
}
三、建树、区间加、单点查询
P3368 【模板】树状数组 2
#include <bits/stdc++.h>
using namespace std;
int n, m, a[500010], x, y, k, opt;
struct SegmentTree
{
int l, r;
long long sum, lazy;
}t[2000010];
//建树 build(1, 1, n);
void build(int p, int l, int r)
{
t[p].l=l;
t[p].r=r;
if(l==r){
t[p].sum=a[l];
return;
}
int mid=(l+r)/2;
build(p*2, l, mid);
build(p*2+1, mid+1, r);
t[p].sum=t[p*2].sum+t[p*2+1].sum;
}
void spread(int p)
{
if(t[p].lazy){
t[p*2].sum+=t[p].lazy*(t[p*2].r-t[p*2].l+1);
t[p*2+1].sum+=t[p].lazy*(t[p*2+1].r-t[p*2+1].l+1);
t[p*2].lazy+=t[p].lazy;
t[p*2+1].lazy+=t[p].lazy;
t[p].lazy=0;
}
}
void change(int p, int l, int r, int d)
{
if(l<=t[p].l && r>=t[p].r){
t[p].sum+=d*(t[p].r-t[p].l+1);
t[p].lazy+=d;
return;
}
spread(p);
int mid=(t[p].l+t[p].r)/2;
if(l<=mid){
change(p*2, l, r, d);
}
if(r>mid){
change(p*2+1, l, r, d);
}
t[p].sum=t[p*2].sum+t[p*2+1].sum;
}
//区间查询 asd(1, l, r);
long long ask(int p, int l, int r)
{
if(l<=t[p].l && r>=t[p].r){ //完全覆盖
return t[p].sum;
}
spread(p); //下传延迟标记
int mid=(t[p].l+t[p].r)/2;
long long ans=0;
if(l<=mid){ //和左子节点有重叠
ans+=ask(p*2, l, r);
}
if(r>mid){ //和右子节点有重叠
ans+=ask(p*2+1, l, r);
}
return ans;
}
int main()
{
scanf("%d %d", &n, &m);
for(int i=1; i<=n; ++i){
scanf("%d", &a[i]);
}
build(1, 1, n);
while(m--){
scanf("%d", &opt);
if(opt==1){
scanf("%d %d %d", &x, &y, &k);
change(1, x, y, k);
}
else if(opt==2){
scanf("%d", &x);
printf("%lld\n", ask(1, x, x));
}
}
return 0;
}
四、建树、区间最大值、最小值查询
P2880 [USACO07JAN] Balanced Lineup G
#include <bits/stdc++.h>
using namespace std;
int n, q, a, b, h[50010];
struct SegmentTree{
int l, r, mx, mn;
}t[200010];
//建树
void build(int p, int l, int r)
{
t[p].l=l;
t[p].r=r;
if(l==r){
t[p].mx=t[p].mn=h[l];
return;
}
int mid=(t[p].l+t[p].r)>>1;
build(p<<1, l, mid);
build(p<<1|1, mid+1, r);
t[p].mx=max(t[p<<1].mx, t[p<<1|1].mx);
t[p].mn=min(t[p<<1].mn, t[p<<1|1].mn);
}
//查询区间最大值
int ask1(int p, int l, int r)
{
if(l<=t[p].l && r>=t[p].r){
return t[p].mx;
}
int mid=(t[p].l+t[p].r)>>1;
int maxans=0;
if(l<=mid){
maxans=max(maxans, ask1(p<<1, l, r)); //ask的时候一定是l到r的
}
if(r>mid){
maxans=max(maxans, ask1(p<<1|1, l, r)); //ask的时候一定是l到r的
}
return maxans;
}
//查询区间最小值
int ask2(int p, int l, int r)
{
if(l<=t[p].l && r>=t[p].r){
return t[p].mn;
}
int mid=(t[p].l+t[p].r)>>1;
int minans=1e7;
if(l<=mid){
minans=min(minans, ask2(p<<1, l, r)); //ask的时候一定是l到r的
}
if(r>mid){
minans=min(minans, ask2(p<<1|1, l, r)); //ask的时候一定是l到r的
}
return minans;
}
int main()
{
scanf("%d %d", &n, &q);
for(int i=1; i<=n; ++i){
scanf("%d", &h[i]);
}
build(1, 1, n);
while(q--){
scanf("%d %d", &a, &b);
printf("%d\n", ask1(1, a, b)-ask2(1, a, b));
}
return 0;
}
P3865 【模板】ST 表
不加快读会有一个点超时
#include <bits/stdc++.h>
using namespace std;
int n, m, a[100010], li, ri;
inline int read()
{
int x=0,f=1;char ch=getchar();
while(ch<'0'||ch>'9'){if (ch=='-') f=-1;ch=getchar();}
while(ch>='0'&&ch<='9'){x=x*10+ch-48;ch=getchar();}
return x*f;
}
struct SegmentTree{
int l, r, mx;
}t[400010];
void build(int p, int l, int r)
{
t[p].l=l;
t[p].r=r;
if(l==r){
t[p].mx=a[l];
return;
}
int mid=(t[p].l+t[p].r)>>1;
build(p<<1, l, mid);
build(p<<1|1, mid+1, r);
t[p].mx=max(t[p<<1].mx, t[p<<1|1].mx);
}
int ask(int p, int l, int r)
{
if(l<=t[p].l && r>=t[p].r){
return t[p].mx;
}
int value=0;
int mid=(t[p].l+t[p].r)>>1;
if(l<=mid){
value=max(value, ask(p<<1, l, r));
}
if(r>mid){
value=max(value, ask(p<<1|1, l, r));
}
return value;
}
int main()
{
scanf("%d %d", &n, &m);
for(int i=1; i<=n; ++i){
a[i]=read();
}
build(1, 1, n);
while(m--){
li=read();
ri=read();
printf("%d\n", ask(1, li, ri));
}
return 0;
}
P2251 质量检测
区间最小值
#include <bits/stdc++.h>
using namespace std;
int n, m, a[100010];
struct SegmentTree
{
int l, r, mn;
}t[400010];
void build(int p, int l, int r)
{
t[p].l=l;
t[p].r=r;
if(l==r){
t[p].mn=a[l];
return;
}
int mid=(t[p].l+t[p].r)>>1;
build(p<<1, l, mid);
build(p<<1|1, mid+1, r);
t[p].mn=min(t[p<<1].mn, t[p<<1|1].mn);
}
int ask(int p, int l, int r)
{
if(l<=t[p].l && r>=t[p].r){
return t[p].mn;
}
int value=10000000;
int mid=(t[p].l+t[p].r)>>1;
if(l<=mid){
value=min(value, ask(p<<1, l, r));
}
if(r>mid){
value=min(value, ask(p<<1|1, l, r));
}
return value;
}
int main()
{
scanf("%d %d", &n, &m);
for(int i=1; i<=n; ++i){
scanf("%d", &a[i]);
}
build(1, 1, n);
for(int i=1; i<=n-m+1; ++i){
printf("%d\n", ask(1, i, i+m-1));
}
return 0;
}
五、区间异或
P2574 XOR的艺术
#include <bits/stdc++.h>
using namespace std;
int n, m, op, l, r, a[200010];
struct SegmentTree
{
int l, r, lazy, sum;
}t[800010];
void build(int p, int l, int r)
{
t[p].l=l;
t[p].r=r;
if(l==r){
t[p].sum=a[l];
return;
}
int mid=(l+r)>>1;
build(p<<1, l, mid);
build(p<<1|1, mid+1, r);
t[p].sum=t[p<<1].sum+t[p<<1|1].sum;
}
void spread(int p)
{
if(t[p].lazy){
if(t[p].lazy%2){
t[p<<1].sum=(t[p<<1].r-t[p<<1].l+1)-t[p<<1].sum;
t[p<<1|1].sum=(t[p<<1|1].r-t[p<<1|1].l+1)-t[p<<1|1].sum;
}
t[p<<1].lazy+=t[p].lazy;
t[p<<1|1].lazy+=t[p].lazy;
t[p].lazy=0;
}
}
void change(int p, int l, int r, int d)
{
if(l<=t[p].l && r>=t[p].r){
t[p].sum=(t[p].r-t[p].l+1)-t[p].sum;
t[p].lazy+=d;
return;
}
spread(p);
int mid=(t[p].l+t[p].r)>>1;
if(l<=mid){
change(p<<1, l, r, d); //注意是l和r
}
if(r>mid){
change(p<<1|1, l, r, d); //注意是l和r
}
t[p].sum=t[p<<1].sum+t[p<<1|1].sum;
}
int ask(int p, int l, int r)
{
if(l<=t[p].l && r>=t[p].r){
return t[p].sum;
}
spread(p);
int mid=(t[p].l+t[p].r)>>1;
int ans=0;
if(l<=mid){
ans+=ask(p<<1, l, r);
}
if(r>mid){
ans+=ask(p<<1|1, l, r);
}
return ans;
}
int main()
{
scanf("%d %d", &n, &m);
for(int i=1; i<=n; ++i){
scanf("%1d", &a[i]);
}
build(1, 1, n);
while(m--){
scanf("%d %d %d", &op, &l, &r);
//将伤害串的 [l,r]区间内的0变成1, 1变成0
if(op==0){ //异或1相当于取反
change(1, l, r, 1);
}
else if(op==1){ //询问伤害串的 [l,r]区间内有多少个字符1
printf("%d\n", ask(1, l, r));
}
}
return 0;
}