线段树 POJ - 3468 A Simple Problem with Integers

地址 https://vjudge.ppsucxtt.cn/problem/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.

解答 题目的大意是
给出一个整数数列, A[1] ~~ A[N]
有以下两个操作
1 Q a b 查询数组A[]中 索引a到索引b所有的数的和
2 C a b c 对数组A[]中 索引a到索引b的所有的数 全部加上一个数c
对于每个操作1的查询 打印出结果 结果占一行

对于线段树方案,这是一个区间更新 区间查询的方案。
对于区间更新,不能高效的实现对一段区域添加一个值,因为需要对这个区间相关的所有节点均进行更新
todo

#define  _CRT_SECURE_NO_WARNINGS
#include <iostream>
#include <vector>
#include <assert.h>
#include <algorithm>

using namespace std;

const int N = 100010;

struct Node {
	int l; int r;
	long long sum;
	long long add;
}t[4 * N];
int arr[N];

int n, m;

void build(int p, int l, int r) {
	t[p].l = l; t[p].r = r;
	if (l == r) { t[p].sum = arr[l]; return; }

	int mid = (l + r) >> 1;
	build(p * 2, l, mid);
	build(p * 2 + 1, mid + 1, r);
	t[p].sum = t[p * 2].sum + t[p * 2 + 1].sum;
}

void pushDown(int p) {
	if (t[p].add) {
		t[p * 2].sum += t[p].add*(t[p*2].r-t[p*2].l+1);
		t[p * 2+1].sum += t[p].add*(t[p * 2+1].r - t[p * 2+1].l + 1);
		t[p * 2].add += t[p].add;
		t[p * 2+1].add += t[p].add;
		t[p].add = 0;
	}
}


void update(int p, int l, int r, int d) {
	if (l <= t[p].l && r >= t[p].r) {
		t[p].sum += (long long)d* (t[p].r - t[p].l + 1);
		t[p].add += d;
		return;
	}
	pushDown(p);
	int mid = (t[p].l + t[p].r) >> 1;
	if (l <= mid) update(p * 2, l, r, d);
	if (r > mid) update(p * 2 + 1, l, r, d);
	t[p].sum = t[p * 2].sum + t[p * 2 + 1].sum;
}


long long query(int p, int l, int r) {
	if (l <= t[p].l && r >= t[p].r) return t[p].sum;
	pushDown(p);
	int mid = (t[p].l + t[p].r) >> 1;
	long long val = 0;
	if (l <= mid) val += query(p * 2, l, r);
	if (r > mid) val += query(p * 2 + 1, l, r);
	return val;
}

int main()
{
	cin >> n >> m;
	for (int i = 1; i <= n; i++) {
		scanf("%d",&arr[i]);
	}
	
	build(1, 1, n);

	for (int i = 0; i < m; i++) {
		char Q[2];
		int j, k, l;
		scanf("%s", &Q);

		if (Q[0] == 'Q') {
			scanf("%d%d",&j,&k);
			printf("%lld\n", query(1,j,k));
		}
		else if(Q[0]=='C') {
			scanf("%d%d%d", &j, &k,&l);
			update(1,j,k,l);
		}
		else {
			assert(0);
		}
	}

	return 0;
}

标记永久化模式

// 111111111111.cpp : 此文件包含 "main" 函数。程序执行将在此处开始并结束。
//
#define _CRT_SECURE_NO_WARNINGS
#include <iostream>
#include <string>
#include <algorithm>

using namespace std;

const int N = 100010;

struct SEGMENT_TREE {
	int l; int r;
	long long sum; long long tag;
}tr[N*4];

int n, q;
int arr[N];

void build(int p,int l,int r ) {
	tr[p].l = l; tr[p].r = r;
	if (l == r) {
		tr[p].tag = 0;
		tr[p].sum = arr[l];
		return;
	}

	int mid = (l + r) >> 1;
	build(p*2,l, mid);
	build(p*2+1,mid + 1, r);
	tr[p].sum = tr[p * 2].sum + tr[p*2+1].sum;
}


long long query(int p, int L, int R) {
	int l = tr[p].l; int r = tr[p].r;

	if (L <= l && r <= R)
		return  tr[p].sum;

	int mid = (l + r) >> 1;
	long long tot = tr[p].tag *(min(r, R) - max(l, L) + 1);
	if (L <= mid) tot += query(p * 2, L, R);
	if (mid < R) tot += query(p * 2 + 1, L, R);

	return tot;
}

void update(int L, int R, int d, int p) {
	int l = tr[p].l; int r = tr[p].r;
	if (L <= l && r <= R) {
		tr[p].tag += d;
		tr[p].sum += d * (r - l + 1);
		return;
	}

	int mid = (l + r) >> 1;
	if (L <= mid) update(L, R, d, p*2);
	if (mid < R) update(L, R, d, p*2+1);
	// pushup 操作需要将当前节点内的标记也算上
	tr[p].sum = tr[p*2].sum + tr[p*2+1].sum + tr[p].tag * (r - l + 1);
}




int main()
{
	scanf("%d%d", &n, &q);

	for (int i = 1; i <= n; i++) {
		scanf("%d",&arr[i]);
	}

	build(1,1,n);

	while (q--) {
		char t[10];
		int L, R, d;
		scanf("%s%d%d", t, &L, &R);
		if (t[0] == 'Q') {
			printf("%lld\n", query(1,L, R));
		}
		else {
			scanf("%d", &d);
			update(L, R, d, 1);
		}
	}
	return 0;
}

我的视频题解空间

posted on 2021-10-05 14:13  itdef  阅读(28)  评论(0编辑  收藏  举报

导航