POJ 3468 【區間修改+區間查詢 樹狀陣列 | 線段樹 | 分塊】
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.
題解1:P200.
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
#define ll long long
using namespace std;
const int maxn = 100000+7;
int n, q, a[maxn];
ll sum[maxn], c[2][maxn];
ll ans = 0;
int lowbit(int x){
return x & -x;
}
ll ask(int k, int x){
ll sum = 0;
while(x){
sum += c[k][x];
x -= lowbit(x);
}
return sum;
}
void add(int k, int x, int y){
while(x <= n){
c[k][x] += y;
x += lowbit(x);
}
}
int main()
{
scanf("%d %d", &n, &q);
for(int i = 1; i <= n; i++){
scanf("%d", &a[i]);
sum[i] = sum[i-1] + a[i];
}
int l, r, w;
while(q--){
char ch[2];
scanf("%s", ch);
if(ch[0] == 'Q'){
ans = 0;
scanf("%d %d", &l, &r);
ans += (sum[r] + (r+1)*ask(0, r) - ask(1, r));
ans -= (sum[l-1] + l*ask(0, l-1) - ask(1, l-1));
printf("%lld\n", ans);
}else{
scanf("%d %d %d", &l, &r, &w);
add(0, l, w);
add(0, r+1, -w);
add(1, l, l*w);
add(1, r+1, -(r+1)*w);
}
}
return 0;
}
方法2:線段樹+延遲標記,P210
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
#define INF -0x3f3f3f3f
#define ll long long
using namespace std;
const int maxn = 100010;
int n, m;
int a[maxn];
struct SegmentTree{
int l, r;
ll sum, add;
#define l(x) t[x].l
#define r(x) t[x].r
#define sum(x) t[x].sum
#define add(x) t[x].add
}t[maxn<<2];
void push_up(int p){
sum(p) = sum(2*p) + sum(2*p+1);
}
void build(int p, int l, int r){
l(p) = l, r(p) = r;
if(l == r){
sum(p) = a[l];
return ;
}
int mid = (l+r)/2;
build(2*p, l, mid);
build(2*p+1, mid+1, r);
push_up(p);
}
void push_down(int p){
if(add(p)){//節點p有標記
sum(2*p) += add(p)*(r(2*p)-l(2*p)+1);//更新左子節點資訊
sum(2*p+1) += add(p)*(r(2*p+1)-l(2*p+1)+1);//更新右子節點資訊
add(2*p) += add(p);//給左子節點打延遲標記
add(2*p+1) += add(p);//給右子節點打延遲標記
add(p) = 0;//清除p的標記
}
}
void change(int p, int l, int r, int d){
if(l <= l(p) && r >= r(p)){//完全覆蓋
sum(p) += d*(r(p)-l(p)+1);//更新節點資訊
add(p) += d;//給節點打延遲標記
return ;
}
push_down(p);//下傳延遲標記
int mid = (l(p)+r(p)) / 2;
if(l <= mid) change(2*p, l, r, d);
if(r > mid) change(2*p+1, l, r, d);
push_up(p);
}
ll ask(int p, int l, int r){
if(l <= l(p) && r >= r(p)){
return sum(p);
}
push_down(p);//下傳延遲標記
int mid = (l(p)+r(p)) / 2;
ll ans = 0;
if(l <= mid) ans += ask(2*p, l, r);
if(r > mid) ans += ask(2*p+1, l, r);
return ans;
}
int main()
{
cin >> n >> m;
for(int i = 1; i <= n; i++){
cin >> a[i];
}
build(1,1,n);
while(m--){
char op[2];
int l, r, d;
scanf("%s%d%d", op, &l, &r);
if(op[0]=='C'){
scanf("%d", &d);
change(1,l,r,d);
}else{
ll ans = ask(1, l, r);
printf("%lld\n", ans);
}
}
return 0;
}
3、分塊,P215
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
#define ll long long
#define INF 0x3f3f3f3f
using namespace std;
const int maxn = 100010;
int n, m, t;
ll sum[maxn], a[maxn], add[maxn];
ll L[maxn], R[maxn];
int pos[maxn];
void change(int l, int r, ll v){
int p = pos[l], q = pos[r];
if(p == q){
for(int i = l; i <= r; i++) a[i] += v;
sum[p] += (r-l+1)*v;
}else{
for(int i = p+1; i <= q-1; i++)
add[i] += v;
for(int i = l; i <= R[p]; i++)
a[i] += v;
sum[p] += (R[p]-l+1)*v;
for(int i = L[q]; i <= r; i++)
a[i] += v;
sum[q] += (r-L[q]+1)*v;
}
}
ll ask(int l, int r){
ll ans = 0;
int p = pos[l], q = pos[r];
if(p == q){
for(int i = l; i <= r; i++)
ans += a[i];
ans += add[p]*(r-l+1);
}else{
for(int i = p+1; i <= q-1; i++)
ans += sum[i] + add[i]*(R[i]-L[i]+1);
for(int i = l; i <= R[p]; i++)
ans += a[i];
ans += add[p]*(R[p]-l+1);
for(int i = L[q]; i <= r; i++)
ans += a[i];
ans += add[q]*(r-L[q]+1);
}
return ans;
}
int main()
{
cin >> n >> m;
for(int i = 1; i <= n; i++){
scanf("%lld", &a[i]);
}
t = int(sqrt(n*1.0));
for(int i = 1; i <= t; i++){
L[i] = int((i-1)*sqrt(n*1.0)) + 1;
R[i] = int(i*sqrt(n*1.0));
}
if(R[t] < n){
t++, L[t] = R[t-1] + 1;
R[t] = n;
}
for(int i = 1; i <= t; i++){
for(int j = L[i]; j <= R[i]; j++){
pos[j] = i;
sum[i] += a[j];
}
}
while(m--){
char op[2];
int l, r;
ll d;
scanf("%s %d %d", op, &l, &r);
if(op[0] == 'C'){
scanf("%lld", &d);
change(l, r, d);
}else{
printf("%lld\n", ask(l, r));
}
}
return 0;
}
相關文章
- 樹狀陣列的區間查詢與區間修改陣列
- POJ 3468 A Simple Problem with Integers(線段樹區間操作)
- POJ 3468 A Simple Problem with Integers (線段樹 區間更新)
- 【樹狀陣列 區間更新區間查詢】code陣列
- 樹狀陣列模板題 & (樹狀陣列 1:單點修改,區間查詢)陣列
- POJ 3468 A Simple Problem with Integers (線段樹 區間共加)
- POJ 3468-A Simple Problem with Integers(區間更新線段樹)
- 芻議線段樹 2 (區間修改,區間查詢)
- POJ3468 A Simple Problem with Integers---樹狀陣列(區間問題)陣列
- POJ 2155-Matrix(二維樹狀陣列-區間修改 單點查詢)陣列
- POJ 1195-Mobile phones(二維樹狀陣列-區間更新區間查詢)陣列
- 樹狀陣列單點更新和區間查詢陣列
- 1082 線段樹練習 3 區間查詢與區間修改
- poj 3237 樹鏈剖分(區間更新,區間查詢)
- 變化的區間樹狀陣列,單點查詢陣列
- HDU1698 Just a Hook【線段樹基礎:區間修改+區間查詢】Hook
- POJ 2777-Count Color(線段樹-區間染色查詢)
- HDU 1556-Color the ball(樹狀陣列-區間修改 單點查詢)陣列
- hihocoder 1078 線段樹的區間修改 (線段樹 區間更新 模板)
- 線段樹(1)建樹、單點修改、單點查詢、區間查詢和例題
- HDU 1556【區間更新+單點查詢 樹狀陣列】陣列
- HDU1166 敵兵佈陣【樹狀陣列 單點修改+區間查詢】陣列
- 關於區間操作查詢(字首和與差分)+樹狀陣列基礎陣列
- HDU1754 I Hate It 【線段樹基礎:點修改+區間查詢】
- 1080 線段樹練習 單點修改及區間查詢
- HDU1166 敵兵佈陣【線段樹基礎:點修改+區間查詢】
- D 區間求和 [數學 樹狀陣列]陣列
- 線段樹+差分——【模板】樹狀陣列2陣列
- 線段樹維護區間等差數列
- 【樹狀陣列 區間修改,單點求值】1556 Color the ball陣列
- 1081 線段樹練習 2 單點查詢及區間修改
- 【Leetcode每日一題】327. 區間和的個數(線段樹/樹狀陣列)LeetCode每日一題陣列
- POJ 2528 Mayor's posters (線段樹 區間更新+離散化)
- POJ 2528 Mayor's posters (線段樹區間更新 + 離散化)
- HYSBZ 2243 樹鏈剖分(區間更新,區間查詢)較難
- 【樹狀陣列 單點修改,區間求值】hdu 1166 敵兵佈陣陣列
- 線段樹(3)——區間操作疊加
- poj 2481 樹狀陣列陣列