日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

洛谷 P3372 【模板】线段树 1(线段树区间加区间找)

發布時間:2024/4/15 编程问答 22 豆豆
生活随笔 收集整理的這篇文章主要介紹了 洛谷 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(线段树区间加区间找)的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。