#写在前面
线段树里一般有俩个操作
- push_up 由子节点算父节点的信息
- push_down 把父节点的修改信息下传到子节点
设倒数第二层有n个点,则除去最后一层有 2n-1 个点,加上最后一层的最坏情况(2n个点)一共有4n-1个点,
对于长度为n的数组,一共有n个叶节点,其倒数第二层的点数必少于 n 个,不妨直接将倒数第二层的点设为n个
直接开4n的数组
还会有一些预留的空间
#最大数
https://www.acwing.com/problem/content/1277/
----c++版
#include<iostream>
#include<algorithm>
#include<cstring>
#include<cstdio>
using namespace std;
const int N=200010;
int m,p;
struct Node{
int l,r;
int v;// 区间最大值 如果是叶节点则为x号叶节点存的值
}tr[N*4];
void pushup(int u){//由子算u
tr[u].v=max(tr[u<<1].v, tr[u<<1|1].v);
}
void build(int u, int l, int r){
tr[u]={l, r};
if(l==r)return;
int mid=l+r>>1;
build(u<<1, l, mid); build(u<<1|1, mid+1, r);
}
int query(int u, int l, int r){
if(tr[u].l>=l && tr[u].r<= r) return tr[u].v;
int mid=tr[u].l+tr[u].r>>1;
int v=0;
if(l<=mid)v=query(u<<1, l, r);
if(r>mid)v=max(v, query(u<<1|1, l, r));
return v;
}
void modify(int u, int x, int v){
if(tr[u].l==x&&tr[u].r==x)tr[u].v=v;
else{
int mid=tr[u].l+tr[u].r>>1;
if(x<=mid)modify(u<<1, x, v);
else modify(u<<1|1, x, v);
pushup(u); //非叶节点才会pushup
}
}
int main(){
int n=0, last=0;
scanf("%d%d", &m, &p);
build(1, 1, m);
int x;
char op[2];
while(m--){
scanf("%s%d", op, &x);
if(*op=='Q'){
last=query(1, n-x+1, n);
printf("%d\n", last);
}else{
modify(1, n+1, (last+x)%p);
n++;
}
}
return 0;
}
#你能回答这些问题吗
https://www.acwing.com/activity/content/problem/content/1608/1/
----c++版
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
using namespace std;
const int N=500010;
int n,m;
int w[N];
struct Node{
int l,r;
int sum, lmax, rmax, tmax;
}tr[N*4];
void pushup(Node &u, Node &l, Node &r){
u.sum=l.sum+r.sum;
u.lmax=max(l.lmax, l.sum+r.lmax);
u.rmax=max(r.rmax, r.sum+l.rmax);
u.tmax=max(max(l.tmax, r.tmax), l.rmax+r.lmax);
}
void pushup(int u){
pushup(tr[u], tr[u<<1], tr[u<<1|1]);
}
void build(int u, int l, int r){
if(l==r)tr[u]={l, r, w[r], w[r], w[r], w[r]};
else{
tr[u]={l,r};
int mid=l+r>>1;
build(u<<1, l, mid); build(u<<1|1, mid+1, r);
pushup(u);
}
}
void modify(int u, int x, int v){
if(tr[u].l==x&&tr[u].r==x)tr[u]={x,x,v,v,v,v};
else{
int mid=tr[u].l+tr[u].r>>1;
if(x<=mid)modify(u<<1,x,v);
else modify(u<<1|1 ,x, v);
pushup(u);
}
}
Node query(int u, int l, int r){
if(tr[u].l>=l&&tr[u].r<=r)return tr[u];
else{
int mid=tr[u].l+tr[u].r>>1;
if(r<=mid)return query(u<<1, l, r);//全在左子区间
else if(l>mid)return query(u<<1|1, l, r);//全在右子区间
else{
auto left=query(u<<1, l, r);
auto right=query(u<<1|1, l, r);
Node res; //这个l, r的区间是新合并出的答案区间
pushup(res, left, right);
return res;
}
}
}
int main(){
scanf("%d%d", &n, &m);
for(int i=1; i<=n; i++) scanf("%d", &w[i]);
build(1,1,n);
int k,x,y;
while(m--){
scanf("%d%d%d", &k, &x, &y);
if(k==1){
if(x>y)swap(x,y);
printf("%d\n", query(1,x,y).tmax);
}
else modify(1,x,y);
}
return 0;
}
#区间的最大公约数
https://www.acwing.com/problem/content/247/
----c++版
#include<iostream>
#include<cstring>
#include<algorithm>
#include<cstdio>
using namespace std;
typedef long long LL;
const int N=500010;
int n,m;
LL w[N];
struct Node{
int l,r;
LL sum, d;
}tr[N*4];
LL gcd(LL a, LL b){
return b? gcd(b, a%b):a;
}
void pushup(Node &u, Node &l, Node &r){
u.sum=l.sum+r.sum;
u.d=gcd(l.d, r.d);
}
void pushup(int u){
pushup(tr[u], tr[u<<1], tr[u<<1|1]);
}
void build(int u, int l, int r){
if(l==r){
LL b=w[r]-w[r-1];
tr[u]={l,r,b,b};
}else{
tr[u].l=l, tr[u].r=r;
int mid=l+r>>1;
build(u<<1, l, mid), build(u<<1|1, mid+1, r);
pushup(u);
}
}
void modify(int u, int x, LL v){
if(tr[u].l==x&&tr[u].r==x){
LL b=tr[u].sum+v;
tr[u]={x,x,b,b};
}else{
int mid=tr[u].l+tr[u].r>>1;
if(x<=mid)modify(u<<1, x, v);
else modify(u<<1|1, x, v);
pushup(u);
}
}
Node query(int u, int l, int r){
if(tr[u].l>=l&&tr[u].r<=r)return tr[u];
else{
int mid=tr[u].l+tr[u].r>>1;
if(r<=mid) return query(u<<1, l, r);
else if(l>mid)return query(u<<1|1, l, r);
else{
auto left=query(u<<1, l, r);
auto right=query(u<<1|1, l, r);
Node res;
pushup(res, left, right);
return res;
}
}
}
int main(){
scanf("%d%d", &n,&m);
for(int i=1; i<=n; i++)scanf("%lld", &w[i]);
build(1, 1, n);
int l, r;
LL d;
char op[2];
while(m--){
scanf("%s%d%d", op, &l, &r);
if(*op=='Q'){
auto left=query(1,1,l);
Node right({0,0,0,0});
if(l+1<=r)right=query(1, l+1, r);// 不能直接用w[l],可能会被修改
printf("%lld\n", abs(gcd(left.sum, right.d)));//差分可能会有负数
}
else{
scanf("%lld", &d);
modify(1, l, d);
if(r+1<=n)modify(1, r+1, -d);
}
}
return 0;
}