AcWing 243. 一个简单的整数问题2

AcWing 243. 一个简单的整数问题2

给定一个长度为N的数列A,以及M条指令,每条指令可能是以下两种之一:

1、“C l r d”,表示把 A[l],A[l+1],…,A[r] 都加上 d。

2、“Q l r”,表示询问 数列中第 l~r 个数的和。

对于每个询问,输出一个整数表示答案。

输入格式
第一行两个整数N,M。

第二行N个整数A[i]。

接下来M行表示M条指令,每条指令的格式如题目描述所示。

输出格式
对于每个询问,输出一个整数表示答案。

每个答案占一行。

数据范围
1≤N,M≤105,
|d|≤10000,
|A[i]|≤1000000000
输入样例:

10 5
1 2 3 4 5 6 7 8 9 10
Q 4 4
Q 1 10
Q 2 4
C 3 6 3
Q 2 4

输出样例:

4
55
9
15

今天上高数发现以前学的都忘的有一点多,拿出一个半小时,今天复习了以前的高数。
今天刚好要学线段树,于是我去做了一下线段树的第一讲,一个简单的整数问题,我想刚好可以入门学一下线段树,然后我就去试着做了一下,不做不知道一做吓一跳,简单个毛线,给大家看个难度图压压惊。
压压惊
然后我就开始仔细的去看y总的视频去学一下线段树,y总没有留下代码,只有树状数组的代码,所以我刚开始学线段树的很尴尬,于是我就把y总写的代码来回翻视频给大家把所有的树的操作过程代码截屏下来了。减少来回翻的繁琐。

y总的视频
下面是各个操作的图
更新目前的值(左右两个子树的的值)
在这里插入图片描述
向下更新左右子节点的值。
在这里插入图片描述
修改 l - r 区间的值(增加k)
在这里插入图片描述
查询操作(从l到r)的和。
在这里插入图片描述
最后说一下代码吧

代码如下

#include<iostream>

using namespace std;

const int N=1e5+10;
typedef long long LL;

int a[N];

struct Node
{
    int l,r;
    LL w,add;//add叫懒人节点,因为这样可以减少操作步数
} trie[N*4];//用结构体保存线段树


void pushup(int u)//更新该点的操作
{
    trie[u].w=trie[u<<1].w+trie[u<<1|1].w;//左右子节点的和
}

void build(int u,int l,int r)//建立线段树
{
    if(l==r)
    {
        trie[u]={l,r,a[l],0};
    }
    else
    {
        trie[u]={l,r};
        int mid=l+r>>1;//这个是我一致bug的操作,应该是l+r
        build(u<<1,l,mid);
        build(u<<1|1,mid+1,r);
        pushup(u);
        trie[u].add=0;
    }
}

void pushdown(int u)//更新左右子树
{
    auto &root=trie[u],&lef=trie[u<<1],&rig=trie[u<<1|1];
    if(root.add)
    {
        lef.add+=root.add;lef.w+=(LL)(lef.r-lef.l+1)*(root.add);
        rig.add+=root.add;rig.w+=(LL)(rig.r-rig.l+1)*(root.add);
        root.add=0;
    }
}

void modify(int u,int l,int r,int k)
{
    if(trie[u].l>=l&&trie[u].r<=r)
    {
        trie[u].add+=k;
        trie[u].w+=(LL)(trie[u].r-trie[u].l+1)*k;//不用懒人节点了
    }
    else
    {
        pushdown(u);//要用到懒人节点先更新
        int mid=trie[u].l+trie[u].r>>1;
        if(l<=mid) modify(u<<1,l,r,k);
        if(mid<r) modify(u<<1|1,l,r,k);
        pushup(u);//最后更新目前的子节点
    }
}

LL query(int u,int l,int r)
{
    if(trie[u].l>=l&&trie[u].r<=r)
    {
        return trie[u].w;
    }
    else
    {
        pushdown(u);//用到懒人节点
        LL res=0;
        int mid=trie[u].l+trie[u].r>>1;
        if(l<=mid) res+=query(u<<1,l,r);
        if(r>mid) res+=query(u<<1|1,l,r);
        return res;
    }
}

int main(void)
{
    int n,m;
    cin>>n>>m;
    for(int i=1;i<=n;i++) cin>>a[i];
    build(1,1,n);
  //  cout<<query(1,1,2)<<endl;
    while(m--)
    {
        char op[2];
        cin>>op;
        if(*op=='Q')
        {
            int a,b;
            cin>>a>>b;
            cout<<query(1,a,b)<<endl;
        }
        else
        {
            int a,b,d;
            cin>>a>>b>>d;
            modify(1,a,b,d);
        }
    }
}
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值