线段树概述

什么题可以使用线段树呢?

线段树要满足一下几个性质:

1.操作可合并

2.查询可合并

3.可以在很短的时间合并操作

线段树没啥可说的,就直接贴份代码算了(区间修改,区间查询)

#include<iostream>  
#include<cstdio>  
#include<cstring>  
#include<string>  
#include<algorithm>  
using namespace std;  
struct lxy{  
    long long num,tag;  
    int lson,rson;  
    int l,r;  
}b[400005];  
int ini[100005];  
int n,m,cnt=0;  

int readit()  
{  
    char a;  
    int x=1,num=0;  
    a=getchar();  
    while((a<'0'||a>'9')&&a!='-')a=getchar();  
    if(a=='-')x=-1,a=getchar();  
    while(a<='9'&&a>='0')  
    {  
        num=num*10+a-'0';  
        a=getchar();  
    }  
    return num*x;  
}  

void update(int u)  
{  
    b[u].num=b[b[u].rson].num+b[b[u].lson].num;  
}  

void pushdown(int u)  
{  
    if(b[u].tag==0)return;  
    int y=b[u].tag;  
    b[b[u].lson].num+=y*(b[b[u].lson].r-b[b[u].lson].l+1);  
    b[b[u].rson].num+=y*(b[b[u].rson].r-b[b[u].rson].l+1);  
    b[b[u].lson].tag+=y;  
    b[b[u].rson].tag+=y;  
    b[u].tag=0;  
}  

void build(int &k,int l,int r)  
{  
    k=++cnt;  
    b[k].l=l;b[k].r=r;  
    if(l==r)  
    {  
        b[k].num=ini[l];  
        return;  
    }  
    int mid=(l+r)/2;  
    build(b[k].lson,l,mid);  
    build(b[k].rson,mid+1,r);  
    update(k);  
}  

void modify(int u,int ql,int qr,int x)  
{  
    pushdown(u);  
    if(ql==b[u].l&&qr==b[u].r)  
    {  
        b[u].num+=x*(b[u].r-b[u].l+1);  
        b[u].tag+=x;  
        return;  
    }  
    int mid=(b[u].l+b[u].r)/2;  
    if(ql>mid) modify(b[u].rson,ql,qr,x);  
    else if(qr<=mid) modify(b[u].lson,ql,qr,x);  
    else {modify(b[u].rson,mid+1,qr,x);modify(b[u].lson,ql,mid,x);}  
    update(u);  
}  

long long ques(int u,int ql,int qr)  
{  
    pushdown(u);  
    if(b[u].l==ql&&b[u].r==qr)  
      return b[u].num;  
    int mid=(b[u].l+b[u].r)/2;  
    long long ret=0;  
    if(ql>mid) ret+=ques(b[u].rson,ql,qr);  
    else if(qr<=mid) ret+=ques(b[u].lson,ql,qr);  
    else ret+=ques(b[u].rson,mid+1,qr)+ques(b[u].lson,ql,mid);  
    update(u);  
    return ret;  
}  

int main()  
{  
    int root=1;  
    n=readit();m=readit();  
    for(int i=1;i<=n;i++)  
      ini[i]=readit();  
    build(root,1,n);  
    for(int i=1;i<=m;i++)  
    {  
        int x;  
        x=readit();  
        if(x==1)  
        {  
            int a1,a2,a3;  
            a1=readit();a2=readit();a3=readit();  
            modify(root,a1,a2,a3);  
        }  
        else  
        {  
            int a1,a2;  
            a1=readit();a2=readit();  
            printf("%lld\n",ques(root,a1,a2));  
        }  
    }  
}  
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值