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

歡迎訪問 生活随笔!

生活随笔

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

编程问答

POJ3468--A Simple Problem with Integers--线段树/树状数组 改段求段

發布時間:2025/4/9 编程问答 25 豆豆
生活随笔 收集整理的這篇文章主要介紹了 POJ3468--A Simple Problem with Integers--线段树/树状数组 改段求段 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

題目描述

You have N integers, A1, A2, ... , AN. You need to deal with two kinds of operations. One type of operation is to add some given number to each number in a given interval. The other is to ask for the sum of numbers in a given interval.

Input

The first line contains two numbers N and Q. 1 ≤ N,Q ≤ 100000.
The second line contains N numbers, the initial values of A1, A2, ... , AN. -1000000000 ≤ Ai ≤ 1000000000.
Each of the next Q lines represents an operation.
"C a b c" means adding c to each of Aa, Aa+1, ... , Ab. -10000 ≤ c ≤ 10000.
"Q a b" means querying the sum of Aa, Aa+1, ... , Ab.

Output

You need to answer all Q commands in order. One answer in a line.

Sample Input

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

Sample Output

4
55
9
15

Hint
The sums may exceed the range of 32-bit integers.

解題思路

不同于改段求點或改點求段,這是一個改段求段的題目
有兩種方法接題:
第一種為利用樹狀數組:

區間更新這里引進了一個數組delta數組,delta[i]表示區間 [i, n] 的共同增量,每次你需要更新的時候只需要更新delta數組就行了,因為每段區間更新的數都記錄在這個數組
中,那怎么查詢前綴和吶?
sum[i]=a[1]+a[2]+a[3]+......+a[i]+delta[1](i-0)+delta[2](i-1)+delta[3](i-2)+......+delta[i](i-i+1);
= sigma( a[x] ) + sigma( delta[x] * (i + 1 - x) )
= sigma( a[x] ) + (i + 1) * sigma( delta[x] ) - sigma( delta[x] * x )

(引用自呂程博客)
具體代碼為

#include<iostream> #include<string.h> #include<stdio.h> using namespace std; const int M=100010; long long add_sum[M]; long long add[M]; long long ori[M]; int MN; int Q; int lowbit(int x) {return x&(-x); } void update(int i,int v,long long* a) {for(;i<=MN;i+=lowbit(i)){a[i]+=v;} } long long getsum(int r,long long *a) {long long resr=0;for(;r>0;r-=lowbit(r)){resr+=a[r];}return resr; } int main() {//freopen("data.in","r",stdin);std::ios::sync_with_stdio(false);std::cin.tie(0);int tem;int l,r,val;while(cin>>MN>>Q){memset(ori,0,sizeof(ori));memset(add_sum,0,sizeof(add_sum));memset(add,0,sizeof(add));for(int i=1;i<=MN;i++){cin>>tem;update(i,tem,ori);}string ch;for(int i=0;i<Q;i++){cin>>ch;if(ch=="Q"){cin>>l>>r;cout<<getsum(r,ori)-getsum(l-1,ori)-l*getsum(l-1,add)+(r+1)*getsum(r,add)-getsum(r,add_sum)+getsum(l-1,add_sum)<<endl;}if(ch=="C"){cin>>l>>r>>val;update(l,val,add);update(r+1,-val,add);update(l,val*(l),add_sum);update(r+1,-val*(r+1),add_sum);}}} }

注意:add_sum數組保存的是add[i]*i之后的值

第二種方法為利用線段樹
可以寫一個利用結構體實現的線段樹,然后加懶標。我地AC代碼是按照劉汝佳的板寫的,我覺得他地方法比較簡潔,更好玩
下面是代碼(詳解見算法競賽入門經典-訓練指南):

#include<iostream> #include<string.h> #include<string> #include<stdio.h> #include<stdlib.h> using namespace std; const int M = 4*100010; long long sumv[M];//線段樹sum數組 long long add[M]; long long x, y;//全局變量,update與query時使用 long long addval; long long _sum; //*********************// void update(int id, int l, int r) {long long m = l + (r - l) / 2;if (x <= l&&y >= r){add[id] += addval;}else{if (x <= m) update(2 * id, l, m);if (y>m) update(2 * id + 1, m+1, r);}sumv[id]=0;//!!!!!!!!!注意此步驟if (l<r){sumv[id] = sumv[2 * id] + sumv[2 * id + 1];}sumv[id] += add[id] * (r - l + 1); } void query(int id, int l, int r, long long addv) {long long m = l + (r - l) / 2;if (x <= l&&y >= r){_sum += sumv[id] + addv*(r - l + 1);}else{//addv += add[id];if (x <= m){query(2 * id, l, m, addv+add[id]);}if (y>m) query(2 * id + 1, m+1, r, addv+add[id]);} } int main() {//freopen("data.in", "r", stdin);//freopen("data.out","w",stdout);std::ios::sync_with_stdio(false);std::cin.tie(0);long long n, q;while (cin >> n >> q){memset(sumv, 0, sizeof(sumv));memset(add, 0, sizeof(add));for (int i = 1; i <= n; i++){cin >> addval;x = i;y = i;update(1, 1, n);}string ch;for (int i = 0; i<q; i++){cin >> ch;if (ch == "Q"){_sum = 0;cin >> x >> y;query(1, 1, n, 0);cout << _sum << endl;}if (ch == "C"){cin >> x >> y >> addval;update(1, 1, n);}}} }

轉載于:https://www.cnblogs.com/liuzhanshan/p/5894121.html

總結

以上是生活随笔為你收集整理的POJ3468--A Simple Problem with Integers--线段树/树状数组 改段求段的全部內容,希望文章能夠幫你解決所遇到的問題。

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