洛谷 P13825:[模板] 线段树 1.5 ← unsigned long long

​【题目来源】
https://www.luogu.com.cn/problem/P13825

【题目描述】
如题,已知一个长度为 n 的数列 {ai}(1≤i≤n),初始时 a 序列满足 ai=i。你需要进行下面两种操作:
(1)将某区间每一个数加上 k。
(2)求出某区间每一个数的和。

【输入格式】
第一行包含两个整数 n,m,分别表示该数列数字的个数和操作的总个数。
接下来 m 行每行包含 3 或 4 个整数,表示一个操作,具体如下:
(1)1 l r k:将区间 [l,r] 内每个数加上 k。
(2)2 l r:输出区间 [l,r] 内每个数的和。

【输出格式】
输出包含若干行整数,即为所有操作 2 的结果。

【输入样例】
5 5
2 2 4
1 2 3 2
2 3 4
1 1 5 1
2 1 4​​​​​​​

【输出样例】
9
9
18​​​​​​​

【数据范围】
对于 30% 的数据,n≤8,m≤10。
对于 50% 的数据,n≤10^5。
对于 100% 的数据,1≤m,k≤10^5,1≤l≤r≤n≤10^9。

【算法分析】
本题数据量大,必须开 unsigned long long,否则最后一个样例会 WA。

【算法代码】

#include <bits/stdc++.h>
using namespace std;

typedef unsigned long long LL;
const int N=6e6+5;

struct Node {
    int le,ri;
    LL sum,add;
} tr[N];
int tot=1;

void pushdown(int u,LL le,LL ri) {
    if(!tr[u].add) return;
    LL mid=le+(ri-le)/2;
    if(!tr[u].le) tr[u].le=++tot;
    if(!tr[u].ri) tr[u].ri=++tot;
    int L=tr[u].le,R=tr[u].ri;
    tr[L].sum+=tr[u].add*(mid-le+1);
    tr[L].add+=tr[u].add;
    tr[R].sum+=tr[u].add*(ri-mid);
    tr[R].add+=tr[u].add;
    tr[u].add=0;
}

void update(int u,LL le,LL ri,LL ul,LL ur,LL k) {
    if(ul<=le && ri<=ur) {
        tr[u].sum+=k*(ri-le+1);
        tr[u].add+=k;
        return;
    }
    pushdown(u,le,ri);
    LL mid=le+(ri-le)/2;
    if(ul<=mid) {
        if(!tr[u].le) tr[u].le=++tot;
        update(tr[u].le,le,mid,ul,ur,k);
    }
    if(ur>mid) {
        if(!tr[u].ri) tr[u].ri=++tot;
        update(tr[u].ri,mid+1,ri,ul,ur,k);
    }
    tr[u].sum=tr[tr[u].le].sum+tr[tr[u].ri].sum;
}

LL query(int u,LL le,LL ri,LL ql,LL qr) {
    if(ql<=le && ri<=qr) return tr[u].sum;
    pushdown(u,le,ri);
    LL mid=le+(ri-le)/2;
    LL res=0;
    if(ql<=mid && tr[u].le) {
        res+=query(tr[u].le,le,mid,ql,qr);
    }
    if(qr>mid && tr[u].ri) {
        res+=query(tr[u].ri,mid+1,ri,ql,qr);
    }
    return res;
}

LL cal_base(LL L,LL R) {
    LL len=R-L+1;
    if(len%2==0) return len/2*(L+R);
    else return (L+R)/2*len;
}

int main() {
    ios::sync_with_stdio(0);
    cin.tie(0);
    LL n,m,le,ri,k;
    cin>>n>>m;
    while(m--) {
        int op;
        cin>>op;
        if(op==1) {
            cin>>le>>ri>>k;
            update(1,1,n,le,ri,k);
        } else {
            cin>>le>>ri;
            LL base=cal_base(le,ri);
            LL inc=query(1,1,n,le,ri);
            cout<<base+inc<<"\n";
        }
    }
    return 0;
}

/*
in:
5 5
2 2 4
1 2 3 2
2 3 4
1 1 5 1
2 1 4

out:
9
9
18
*/



【参考文献】
https://blog.csdn.net/hnjzsyjyj/article/details/157297587
https://blog.csdn.net/hnjzsyjyj/article/details/152356965
https://blog.csdn.net/hnjzsyjyj/article/details/152364284
https://blog.csdn.net/hnjzsyjyj/article/details/157329299

 

​

posted @ 2026-11-11 16:58  Triwa  阅读(4)  评论(0)    收藏  举报