线段树大合集


1.最大数
在这里插入图片描述

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>

using namespace std;

typedef long long ll;
const int N = 200005;
int m,p;

struct Tree{
    
    
    int l,r;
    int v;  //最大值属性.
}tr[N * 4];

void pushup(int u){
    
    
    tr[u].v = max(tr[u<<1].v,tr[u<<1|1].v);
}

// 由于不更新属性值,所以不需要向上向下传递影响(push)
void build(int u,int l,int r){
    
    
    tr[u] = {
    
    l,r};  // ?
    if(l==r){
    
    
        // tr[u] = {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(l<=tr[u].l && tr[u].r<=r)    return tr[u].v;

    int v = 0;
    int mid = (tr[u].l + tr[u].r) >> 1;
    if(l<=mid)  v = query(u<<1,l,r);
    if(r>mid)   v = max(v,query(u<<1|1,l,r));
    // pushup(u);
    return v;
}

void motify(int u,int x,int val){
    
      // 单点修改:从根节点开始查询到x,修改其属性为val;后进行pushup操作(向上传递影响)
    if(tr[u].l==x && tr[u].r==x){
    
    
        tr[u].v = val;
        return;
    }

    int mid = (tr[u].l + tr[u].r) >> 1;
    if(x<=mid){
    
    
        motify(u<<1,x,val);
    }else{
    
    
        motify(u<<1|1,x,val);
    }
    pushup(u);
}

int main()
{
    
    
    scanf("%d%d",&m,&p);
    build(1,1,m);

    char s[2];
    int x;
    int n = 0;
    int last = 0;
    while(m--){
    
    
        scanf("%s%d",s,&x);

        if(*s=='Q'){
    
    
            last = query(1,n-x+1,n);

            printf("%d\n",last);
        }else{
    
    
            motify(1,n+1,((ll)last+x)%p);
            n++;
        }
    }

    return 0;
}

  1. 单点修改,区间查询
    在这里插入图片描述

线段树存储差分数组.

某一区间上的最大子段和分为三种情况:(取max)
1.左子区间上的最大子段和.
2.右子区间上的最大子段和.
3.横跨两个区间的最大子段和(左子区间上的右连续最大子段和+右子区间上的左连续最大子段和).

计算某一区间上的最大左连续子段和分为两种情况:(取max)
1.左子区间的最大左连续子段和.
2.左子段和+右子区间的最大左连续子段.

需要维护线段树属性:
最大子段和、左连续最大子段和、右连续最大子段和、区间和.

#include <cstdio>
#include <cstring>
#include <cmath>

using namespace std;

const int N = 500010;
int n,m;

struct Node{
    
    
    int l,r;
    int tmax,lmax,rmax,sum;
}tr[N*4];
int w[N];

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);
    }

}

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;
        }
    }
}

void modify(int u,int x,int val){
    
    
    if(tr[u].l==x && tr[u].r==x)    tr[u] = {
    
    x,x,val,val,val,val};
    else{
    
    
        int mid = (tr[u].l + tr[u].r) >> 1;
        if(x<=mid)  modify(u<<1,x,val);
        else  modify(u<<1|1,x,val);
        pushup(u);
    }
}

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);
            auto ans = query(1,x,y);
            printf("%d\n",ans.tmax);
        }else{
    
    
            modify(1,x,y);
        }
    }

    return 0;
}

3.简单的整数问题(区间查询,区间修改,使用懒标记)在这里插入图片描述

#include <iostream>
#include <cstdio>
#include <cstring>

using namespace std;

typedef long long ll;

const int N = 100010;
int n,m;
int w[N];

struct Tree{
    
    
    int l,r;
    ll sum,add;
}tr[N*4];

void pushup(int u){
    
    
    tr[u].sum = tr[u<<1].sum + tr[u<<1|1].sum;
}

void pushdown(int u){
    
    
    Tree &root = tr[u];
    Tree &l = tr[u<<1];
    Tree &r = tr[u<<1|1];

    if(root.add){
    
    
        l.add += root.add, l.sum += (ll)(l.r - l.l + 1)*root.add;
        r.add += root.add, r.sum += (ll)(r.r - r.l + 1)*root.add;
        root.add = 0;
    }
}

void build(int u,int l,int r){
    
    
    tr[u] = {
    
    l,r};
    if(l==r){
    
    
        tr[u] = {
    
    l,l,w[l],0};
        return;
    }

    int mid = (l+r)>>1;
    build(u<<1,l,mid);
    build(u<<1|1,mid+1,r);
    pushup(u);
}

ll query(int u,int l,int r){
    
    
    if(tr[u].l>=l && tr[u].r<=r)    return tr[u].sum;

    pushdown(u);
    ll sum = 0;
    int mid = (tr[u].l + tr[u].r) >> 1;
    if(l<=mid)   sum += query(u<<1,l,r);
    if(r>mid)   sum += query(u<<1|1,l,r);

    return sum;
}

void modify(int u,int l,int r,int d){
    
    
    if(tr[u].l>=l && tr[u].r<=r){
    
    
        tr[u].sum += (tr[u].r - tr[u].l + 1)*d;
        tr[u].add += d;
        return;
    }

    pushdown(u);
    int mid = (tr[u].l + tr[u].r) >> 1;
    if(l<=mid)  modify(u<<1,l,r,d);
    if(r>mid)   modify(u<<1|1,l,r,d);
    pushup(u);
}

int main()
{
    
    
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;i++)   scanf("%d",&w[i]);
    build(1,1,n);

    while(m--){
    
    
        char str[3];
        int l,r,d;

        scanf("%s%d%d",str,&l,&r);

        if(*str=='Q'){
    
    
            printf("%lld\n",query(1,l,r));
        }else{
    
    
            scanf("%d",&d);
            modify(1,l,r,d);
        }
    }

    return 0;
}

4.维护序列
在这里插入图片描述

#include <iostream>
#include <cstdio>
#include <cstring>

using namespace std;

typedef long long ll;

const int N = 100010;
int n,p,m;
int w[N];

struct Tree{
    
    
    int l,r;
    int sum,add,mul;
}tr[N*4];

void eval(Tree &t,int add,int mul){
    
    
    t.sum = ((ll)t.sum * mul + (ll)(t.r - t.l + 1) * add) % p;
    t.mul = ((ll)t.mul * mul) % p;
    t.add = ((ll)t.add * mul + add) % p;
}

void pushup(int u){
    
    
    tr[u].sum = (tr[u<<1].sum + tr[u<<1|1].sum) % p;
}

void pushdown(int u){
    
    
    eval(tr[u<<1],tr[u].add,tr[u].mul);
    eval(tr[u<<1|1],tr[u].add,tr[u].mul);
    tr[u].add = 0,tr[u].mul = 1;
}

void build(int u,int l,int r){
    
    
 
    if(l==r){
    
    
        tr[u] = {
    
    l,l,w[l],0,1};
    }else{
    
    
        tr[u] = {
    
    l,r,0,0,1};   
        int mid = (l + r) >> 1;
        build(u<<1,l,mid);
        build(u<<1|1,mid+1,r);
    
        pushup(u);
    }


}

int query(int u,int l,int r){
    
    
    if(tr[u].l>=l && tr[u].r<=r)    return tr[u].sum;
    
    pushdown(u);
    int sum = 0;
    int mid = (tr[u].l + tr[u].r) >> 1;
    if(l<=mid)  sum = query(u<<1,l,r);
    if(r>mid)   sum = (sum + query(u<<1|1,l,r))%p;
    
    return sum;   
}
    

void modify(int u,int l,int r,int add,int mul){
    
    
    if(tr[u].l>=l && tr[u].r<=r)    eval(tr[u],add,mul);
    else{
    
    
        pushdown(u);
        int mid = (tr[u].l + tr[u].r) >> 1;
        if(l<=mid)  modify(u<<1,l,r,add,mul);
        if(r>mid)   modify(u<<1|1,l,r,add,mul);
        pushup(u);
    }
}

int main()
{
    
    
    scanf("%d%d",&n,&p);
    
    for(int i=1;i<=n;i++)   scanf("%d",&w[i]);
    build(1,1,n);
    scanf("%d",&m);
    
    int op,l,r;
    int v;
    while(m--){
    
    
        scanf("%d%d%d",&op,&l,&r);
        
        if(op==1){
    
    
            scanf("%d",&v);
            modify(1,l,r,0,v);
        }else if(op==2){
    
    
            scanf("%d",&v);
            modify(1,l,r,v,1);
        }else{
    
    
            printf("%d\n",query(1,l,r));
        }
    }
    
    return 0;
}

最后放一道debug了两个小时都不知道问题在哪的代码 nanshou ):
题目链接:线段树
在这里插入图片描述

#include <iostream>
#include <cstdio>
#include <cstring>

using namespace std;

typedef long long ll;

const int N = 100010;

int n,m,p;
int w[N];
int inv2;

struct Tree{
    
    
    int l,r;
    int sum,qsum;    //维护区间和与区间平方和.
    int add,mul;
}tr[N*4];

int cal(int s1,int s2){
    
    
    int ans = (((ll)s1*s1%p - (ll)s2 + p)%p*(ll)inv2%p) % p;
    return ans;
}

//完全正确.
void eval(Tree &t,int add,int mul){
    
    
    int m = (t.l+t.r)/2;
//     t.qsum = ((ll)t.qsum * mul * mul%p + (ll)(t.r - t.l + 1)*add*add%p + (ll)2*add*t.sum*mul%p + p)%p;   //可能会出错.
    t.qsum = ((ll)t.qsum * mul %p * mul % p + (ll)(t.r - t.l + 1ll)*add%p*add%p + (ll)2ll*add%p*t.sum%p*mul%p + p)%p;
//     t.qsum = ((ll)t.qsum * mul %p * mul % p + (ll)(m - t.l + 1ll)*add%p*add%p + (ll)2ll*add%p*t.sum%p*mul%p + p)%p;
    t.sum = ((ll)t.sum * mul + (ll)(t.r - t.l + 1ll) * add) % p;
    t.mul = ((ll)t.mul * mul) % p;
    t.add = ((ll)t.add * mul + (ll)add) % p;
}

// 正确.
void pushup(int u){
    
    
    tr[u].sum = ((ll)tr[u<<1].sum + (ll)tr[u<<1|1].sum + p)%p;
    tr[u].qsum = ((ll)tr[u<<1].qsum + (ll)tr[u<<1|1].qsum + p)%p;
}

//正确
void pushdown(int u){
    
    
    eval(tr[u<<1],tr[u].add,tr[u].mul);
    eval(tr[u<<1|1],tr[u].add,tr[u].mul);
    tr[u].add = 0,tr[u].mul = 1;
}

void build(int u,int l,int r){
    
    
    if(l==r){
    
    
        tr[u] = {
    
    l,l,w[l],w[l]*w[l],0,1};
        return;
    }
    
    tr[u] = {
    
    l,r,0,0,0,1};
    int mid = (l + r) >> 1;
    build(u<<1,l,mid);
    build(u<<1|1,mid+1,r);
    pushup(u);
}

void modify(int u,int l,int r,int add,int mul){
    
    
    if(tr[u].l>=l && tr[u].r<=r){
    
    
        eval(tr[u],add,mul);
        return;
    }
    
    pushdown(u);
    int mid = (tr[u].l + tr[u].r) >> 1;
    if(l<=mid)    modify(u<<1,l,r,add,mul);
    if(r>mid)    modify(u<<1|1,l,r,add,mul);
    pushup(u);
}

int query(int u,int l,int r){
    
    
    if(tr[u].l>=l && tr[u].r<=r)    return cal(tr[u].sum,tr[u].qsum);
    
    pushdown(u);
    int mid = (tr[u].l + tr[u].r) >> 1;
    int sum = 0;
    if(l<=mid)    sum = query(u<<1,l,r);
    if(r>mid)    sum = ((ll)sum + (ll)query(u<<1|1,l,r) + p)%p;
    
    return sum;
}

int quick_pow(int a,int b,int mod){
    
    
    int ans = 1;
    while(b){
    
    
        if(b&1)    ans = (ans * (ll)a) % mod;
        a = ((ll)a * a) % mod;
        b >>= 1;
    }
    return ans;
}

int main()
{
    
    
    int t;
    scanf("%d",&t);
    
    while(t--){
    
    
        int n,m,p;
        scanf("%d%d%d",&n,&m,&p);
        for(int i=1;i<=n;i++)    scanf("%d",&w[i]);
        
        inv2 = quick_pow(2ll,p-2,p);   //求逆元.
        build(1,1,n);
        while(m--){
    
    
            int t,l,r,v;
            scanf("%d%d%d",&t,&l,&r);
            
            if(t==1){
    
    
                scanf("%d",&v);
                modify(1,l,r,v,1);
            }else if(t==2){
    
    
                scanf("%d",&v);
                modify(1,l,r,0,v);
            }else{
    
    
                printf("%d\n",query(1,l,r));
            }
        }
    }
    
    return 0;
}

线段树好鸡儿难写,落泪了…

猜你喜欢

转载自blog.csdn.net/m0_50435987/article/details/121182402