洛谷 P3372 【模板】线段树 1(线段树区间加区间找)
生活随笔
收集整理的這篇文章主要介紹了
洛谷 P3372 【模板】线段树 1(线段树区间加区间找)
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
題目描述
如題,已知一個數列,你需要進行下面兩種操作:
1.將某區間每一個數加上x
2.求出某區間每一個數的和
輸入格式
第一行包含兩個整數N、M,分別表示該數列數字的個數和操作的總個數。
第二行包含N個用空格分隔的整數,其中第i個數字表示數列第i項的初始值。
接下來M行每行包含3或4個整數,表示一個操作,具體如下:
操作1: 格式:1 x y k 含義:將區間[x,y]內每個數加上k
操作2: 格式:2 x y 含義:輸出區間[x,y]內每個數的和
輸出格式
輸出包含若干行整數,即為所有操作2的結果。
輸入輸出樣例
輸入 #1 復制 5 5 1 5 4 2 3 2 2 4 1 2 3 2 2 3 4 1 1 5 1 2 1 4 輸出 #1 復制 11 8 20說明/提示
時空限制:1000ms,128M
數據規模:
對于30%的數據:N<=8,M<=10
對于70%的數據:N<=1000,M<=10000
對于100%的數據:N<=100000,M<=100000
(數據已經過加強^_^,保證在int64/long long數據范圍內)
樣例說明:
#include <cstdio> #include <iostream> #include <cmath> #include <string> #include <cstring> #include <algorithm> #include <queue> #include <vector> #include <map> using namespace std;#define ll long long #define eps 1e-9const int inf = 0x3f3f3f3f; const int mod = 1e9+7;ll n, m, a[1000000+8], ans;struct node {ll left, right, sum, lz; }tree[1000000+8];void build(ll left, ll right, ll i)///建樹 {tree[i].lz = 0;///懶惰標記初始化為0tree[i].left = left;tree[i].right = right;if(left == right)///如果已經是葉子結點 {tree[i].sum = a[left];return ;}ll mid = (right+left)/2;build(left, mid, i*2);///往左邊的區間進行建樹build(mid+1, right, i*2+1);///往右邊的區間進行建樹tree[i].sum = tree[i*2].sum+tree[i*2+1].sum;///自己的和等于左兒子和右兒子的和 }void push_down(ll i)///把自己的lazytage歸零,并給自己的兒子加上,并讓自己的兒子加上k*(r-l+1) {if(tree[i].lz != 0)///如果這個點已經被標記了 {tree[i*2].lz += tree[i].lz;///左兒子的懶惰標記等于父親的懶惰標記tree[i*2+1].lz += tree[i].lz;///右兒子的懶惰標記等于父親的懶惰標記ll mid = (tree[i].left+tree[i].right)/2;tree[i*2].sum += tree[i].lz*(mid-tree[i*2].left +1);///左兒子的和等于它所控制的區間的和tree[i*2+1].sum += tree[i].lz*(tree[i*2+1].right-mid);///右兒子的和等于它所控制的區間的和tree[i].lz = 0;///父節點懶惰標記歸零 }return ; }void pls(ll i, ll l, ll r, ll k)///區間加 {if(tree[i].right <= r && tree[i].left >= l)///如果這個區間就在目標區間的內部 {tree[i].sum += k*(tree[i].right-tree[i].left+1);///這個區間的和 等于(這個區間原本的和)+(k*這個區間的元素個數)tree[i].lz += k;///懶惰標記,表示它已經加了kreturn ;}push_down(i);///把自己的lazytage歸零,并給自己的兒子加上,并讓自己的兒子加上k*(r-l+1)if(tree[i*2].right >= l)///如果這個區間與左邊部分區間重疊,就往左邊區間每個元素加上kpls(i*2, l, r, k);if(tree[i*2+1].left <= r)///如果這個區間與右邊部分區間重疊,就往右邊區間每個元素加上kpls(i*2+1, l, r, k);tree[i].sum = tree[i*2].sum+tree[i*2+1].sum;///父節點的和等于左兒子的和加右兒子的和return ; }void search(ll i, ll l, ll r)///查找區間和 {if(tree[i].left >= l && tree[i].right <= r)///如果這個區間就在目標區間的內部 {ans += tree[i].sum;return ;}if(tree[i].lz)push_down(i);///一層一層的進行標記,方便后來的查找區間和ll mid = (tree[i].left+tree[i].right)/2;if(l <= mid)///如果這個區間與左邊部分區間重疊,就 ans + 左邊區間每個元素加上ksearch(i*2, l, r);if(mid<r)///如果這個區間與右邊部分區間重疊,就 ans + 右邊區間每個元素加上ksearch(i*2+1, l, r); }int main() {scanf("%lld%lld", &n, &m);for(ll i = 1; i <= n; i++)scanf("%lld", &a[i]);build(1, n, 1);///初始化線段樹for(ll i = 1; i <= m; i++){ll f;scanf("%lld", &f);if(f == 1){ll x, y, z;scanf("%lld%lld%lld", &x, &y, &z);pls(1, x, y, z);///從根節點開始進行區間加c }else if(f == 2){ll x, y;scanf("%lld%lld", &x, &y);ans = 0;search(1, x, y);printf("%lld\n", ans);///輸出區間[a, b]的值 }}return 0; }?
轉載于:https://www.cnblogs.com/RootVount/p/11285251.html
總結
以上是生活随笔為你收集整理的洛谷 P3372 【模板】线段树 1(线段树区间加区间找)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 【python】闭包
- 下一篇: Selenium+java - 下拉框处