线段树

Posted zhshh

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了线段树相关的知识,希望对你有一定的参考价值。

线段树

标签(空格分隔): @zhshh 线段树


先留下代码,解析什么的以后再放,。。。估计到时候代码都忘了。。

单标记

洛谷P3372 【模板】线段树 1

#include <iostream>
#include <cstring>
#include <cstdio>
#include <algorithm>
#define MAX 100000+10
using namespace std;

int n, m;
struct node {
    int left, right;
    long long x, mark;
} tree[MAX<<2];
int a [MAX];
void pushup(int root)
{
    tree[root].x = tree[root * 2].x + tree[root * 2 + 1].x;
}

void pushdown(int root,int d)
{
    if (tree[root].mark) {
        tree[root * 2].x += tree[root].mark*(d-d/2);
        tree[root * 2 + 1].x += tree[root].mark*(d/2);
        tree[root * 2].mark += tree[root].mark;
        tree[root * 2 + 1].mark += tree[root].mark;
        tree[root].mark = 0;
    }
}

void update(int left, int right, int c, int root)
{
    if (left <= tree[root].left && right >= tree[root].right) {
        tree[root].mark += c;
        tree[root].x += (tree[root].right - tree[root].left + 1) * c;
        return;
    }
    pushdown(root, tree[root].right - tree[root].left + 1);
    int mid = (tree[root].left + tree[root].right) / 2;
    if (left <= mid)
        update(left, right, c, root * 2);
    if (right > mid)
        update(left, right, c, root * 2 + 1);
    pushup(root);
}

long long query(int left, int right, int root)
{
    if (left <= tree[root].left && right >= tree[root].right)
        return tree[root].x;
    pushdown(root, tree[root].right - tree[root].left + 1);
    int mid = (tree[root].left + tree[root].right) / 2;
    long long ans = 0;
    if (left <= mid)
        ans += query(left, right, root * 2);
    if (right > mid)
        ans += query(left, right, 2 * root + 1);
    return ans;
}

void build (int root,int left,int right)
{
    tree[root].left=left;
    tree[root].right=right;
    if(left==right) {
        tree[root].x=a[left];
    } else {
        int mid=(left+right)/2;
        build(2*root,left,mid);
        build(2*root+1,mid+1,right);
        tree[root].x=tree[2*root].x+tree[2*root+1].x;
    }

}
int main()
{
//  freopen("al1.txt","r",stdin);
    cin>>n>>m;
    for(int i=1; i<=n; i++)cin>>a[i];
    build(1,1,n);
    int ope;
    int q1,q2,q3;
    for(int qwe=1; qwe<=m; qwe++) {
        //  for(int i=1;i<=n;i++)cout<<query(i,i,1)<<"~";
        //  cout<<endl;
        cin>>ope;
        if(ope==1) {
            cin>>q1>>q2>>q3;
            update(q1,q2,q3,1);
        } else {
            cin>>q1>>q2;
            cout<<query(q1,q2,1);
            cout<<endl;
        }
    }
}

双标记

洛谷P3373 【模板】线段树 2

#include <iostream>
#include <cstdio>
#define LL unsigned long long
#define MAX 100010
using namespace std;
struct node {
    int left,right;
    LL add,mul,val;
    node(){
        mul=1;
        add=0;
    }
}tree[MAX<<2];
LL a[MAX];
int n;
LL mod;
void pushup(const int root){
    tree[root].val=(tree[root*2].val+tree[root*2+1].val);
}
void pushdown(const int root){
    if(tree[root].mul!=1 || tree[root].add!=0){
        tree[root<<1].val=(tree[root<<1].val*tree[root].mul)%mod;
        tree[root<<1].val=(tree[root<<1].val+tree[root].add*(tree[root<<1].right-tree[root<<1].left+1))%mod;
        tree[root<<1].add=(tree[root<<1].add*tree[root].mul)%mod;
        tree[root<<1].add=(tree[root<<1].add+tree[root].add)%mod;
        tree[root<<1].mul=(tree[root<<1].mul*tree[root].mul)%mod;
        
        tree[(root<<1)+1].val=(tree[(root<<1)+1].val*tree[root].mul)%mod;
        tree[(root<<1)+1].val=(tree[(root<<1)+1].val+tree[root].add*(tree[(root<<1)+1].right-tree[(root<<1)+1].left+1))%mod;
        tree[(root<<1)+1].add=(tree[(root<<1)+1].add*tree[root].mul)%mod;
        tree[(root<<1)+1].add=(tree[(root<<1)+1].add+tree[root].add)%mod;
        tree[(root<<1)+1].mul=(tree[(root<<1)+1].mul*tree[root].mul)%mod;
        
        tree[root].mul=1;
        tree[root].add=0;
    }
}
void add(const int root,const int left,const int right, const int c){
    if(left<=tree[root].left && right>=tree[root].right){
        tree[root].add=(tree[root].add+c)%mod;
        tree[root].val=(tree[root].val+c*(tree[root].right-tree[root].left+1))%mod;
        return ;
    }
    pushdown(root);
    int mid=(tree[root].left+tree[root].right)/2;
    if(left<=mid)add(root*2,left,right,c);
    if(right>mid)add(root*2+1,left,right,c);
    pushup(root);
    return ;
}
void mul(const int root,const int left,const int right,const int k){
    if(left<=tree[root].left && right>=tree[root].right){
        tree[root].mul=(tree[root].mul*k)%mod;
        tree[root].add=(tree[root].add*k)%mod;
        tree[root].val=(tree[root].val*k)%mod;
        return ;
    }
    pushdown(root);
    int mid=(tree[root].left+tree[root].right)/2;
    if(left<=mid)mul(root*2,left,right,k);
    if(right>mid)mul(root*2+1,left,right,k);
    pushup(root);
    return ;
}
int query(const int root,const int left,const int right){
    if(left<=tree[root].left && right>=tree[root].right){
        return tree[root].val;
    }
    pushdown(root);
    int mid=(tree[root].left+tree[root].right)/2;
    LL ans=0;
    if(left<=mid)ans=(ans+query(root*2,left,right))%mod;
    if(right>mid)ans=(ans+query(root*2+1,left,right))%mod;
    return ans;
}
void build(const int root,const int left,const int right){
    tree[root].left=left;
    tree[root].right=right;
    if(left==right){
        tree[root].val=a[left];
        return ;
    }
    int mid=(tree[root].left+tree[root].right)/2;
    build(root*2,left,mid);
    build(root*2+1,mid+1,right);
    pushup(root);
    return ;
}
void pr(){
    for(int i=1;i<=n;i++){
        cout<<query(1,i,i)<<endl;
    }
    cout<<endl;
}
int main(){
    int m,t1,t2,t3;
    cin>>n>>m>>mod;
    for(int i=1;i<=n;i++){
        cin>>a[i];
        a[i]%=mod;
    }
    build(1,1,n);
    for(int i=1;i<=m;i++){
        cin>>t1;
        if(t1==1){
            cin>>t1>>t2>>t3;
            mul(1,t1,t2,t3);
        }else{
            if(t1==2){
                cin>>t1>>t2>>t3;
                add(1,t1,t2,t3);
            }else{
                cin>>t1>>t2;
                cout<<query(1,t1,t2)<<endl;
            }
        }
    }
}

以上是关于线段树的主要内容,如果未能解决你的问题,请参考以下文章

线段树

CCF(除法):线段树区间修改(50分)+线段树点修改(100分)+线段树(100分)

线段树合并

数据结构——线段树

论线段树:二

线段树