本文为原创,转载请注明:http://www.cnblogs.com/kylewilson/

题目出处:

http://poj.org/problem?id=3468

题目描述:

给N个数A1A2, ... , AN. 你需要处理两种操作,一种操作是在一个区间上每个数都增加一个数,别一种操作是查询一个区间所有数的和

输入

第一行两个数N, Q, 1 ≤ N,Q ≤ 100000

第二行N个数,数组初始值A1A2, ... , AN. -1000000000 ≤ Ai ≤ 1000000000.

接着Q行,表示Q次操作"C a b c" 表示区间AaAa+1, ... , Ab.,第个数增加c,  -10000 ≤ c ≤ 10000.

"Q a b"  表示查询区间Aa, Aa+1, ... , Ab之和

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

思路分析:

首先分析数据规模,如果有简单模拟算法,时间复杂度O(N*Q),肯定会超时;

看题目需求,每次输入都是对区间进行增加或者查询等操作,所以也必须用区间操作算法来解决;

此文以线段树来解决,树状数组也很适合解决此类问题。事实证明能用树状数组解决的都可以用线段树来解决,反之则不行;

线段树维护区间信息,而树状数组维护前缀和信息;

如上图P1.1,对于增加操作如(a=0, b=2, c=1),需要对[0,2]区间每个点进行增加,但如果递归所有子树去增加操作,就退化成了线性;

所以遍历到[0,2]区间时,只对该点操作,并记录以该点以根的子树,应该增加的值,先记录,下次遍历到子树再执行操作

如上图P1.2,对[0,2]执行了操作,再子树还没有增加,如果下次查询子树则数据错误,所以每次在执行增加或者查询操作的时候,就把上次遗留下来的数据给补上,也就是所谓的Lazy思想。

每个树节点主要记录如下信息:

left: 区间左起点

right: 区间右终点

total: 区间和

childrenExtra: 子树还应该额外增加的值

lson, rson: 左右子树

注:因题目数据量大,输入输出用scanf, printf,如果用cin, cout则会超时。

C++源码如下:

github: https://github.com/Kyle-Wilson1/Poj/tree/master/P3468

#include <iostream>
#include <fstream>
#include <vector> using namespace std; struct SegmentTree {
long long left, right, total, childrenExtra;
SegmentTree *lson, *rson;
}; long long regionLength(SegmentTree *tree) {
return tree->right - tree->left + 1;
} void updateChildren(SegmentTree *root) {
if (root->lson != NULL && root->rson != NULL && root->childrenExtra != 0) {
root->lson->total += root->childrenExtra * regionLength(root->lson);
root->lson->childrenExtra += root->childrenExtra;
root->rson->total += root->childrenExtra * regionLength(root->rson);
root->rson->childrenExtra += root->childrenExtra;
root->childrenExtra = 0;
}
} SegmentTree *buildTree(vector<long long> &num, long long l, long long r) {
if (l > r) {
return NULL;
}
if (l == r) {
SegmentTree *root = new SegmentTree;
root->left = l;
root->right = r;
root->total = num[l];
root->childrenExtra = 0;
root->lson = NULL;
root->rson = NULL;
return root;
}
SegmentTree *root = new SegmentTree;
root->left = l;
root->right = r;
root->childrenExtra = 0;
long long mid = (l + r) >> 1;
root->lson = buildTree(num, l, mid);
root->rson = buildTree(num, mid + 1, r);
root->total = root->lson->total + root->rson->total;
return root;
} void addRegion(SegmentTree *root, long long regionLeft, long long regionRight, long long addNum) {
if (root == NULL || root->right < regionLeft || root->left > regionRight) {
return;
}
if (root->left >= regionLeft && root->right <= regionRight) {
root->total += addNum * regionLength(root);
if (root->left < root->right)root->childrenExtra += addNum;
return;
}
updateChildren(root);
addRegion(root->lson, regionLeft, regionRight, addNum);
addRegion(root->rson, regionLeft, regionRight, addNum);
root->total = root->lson->total + root->rson->total;
} void queryRegion(SegmentTree *root, long long regionLeft, long long regionRight, long long &sum) {
if (root == NULL || root->right < regionLeft || root->left > regionRight) {
return;
}
if (root->left >= regionLeft && root->right <= regionRight) {
sum += root->total;
return;
}
updateChildren(root);
queryRegion(root->lson, regionLeft, regionRight, sum);
queryRegion(root->rson, regionLeft, regionRight, sum);
}

int main() {
ifstream fin("a.in");
ofstream fout("a.out"); long long n, q, i, a, b, c;
char type[2];
SegmentTree *root; // scanf("%lld%lld", &n, &q);
fin >> n >> q; vector<long long> num(n, 0); for (i = 0; i < n; i++) {
// scanf("%lld", &num[i]);
fin >> num[i];
} n--;
root = buildTree(num, 0, n); for (i = 0; i < q; i++) {
// scanf("%s", type);
fin >> type;
if (type[0] == 'C') {
// scanf("%lld%lld%lld", &a, &b, &c);
fin >> a >> b >> c;
addRegion(root, a - 1, b - 1, c);
} else {
// scanf("%lld%lld", &a, &b);
fin >> a >> b;
long long sum = 0;
queryRegion(root, a - 1, b - 1, sum);
// printf("%lld\n", sum);
fout << sum << endl;
}
} return 0;
}

最新文章

  1. Windows下Nginx配置SSL实现Https访问(包含证书生成)
  2. KPI:Key Performance Indicator
  3. android获取本地图片并显示图片
  4. HibernateUtil
  5. 浅谈T-SQL中的特殊联结
  6. HDOJ 4497 GCD and LCM
  7. Linux之文件系统的简单操作
  8. 【转】【玩转cocos2d-x之二十三】多线程和同步03-图片异步加载
  9. 2014年acm亚洲区域赛&#183;鞍山站
  10. oracle创建实例SID
  11. SelectSort 选择排序
  12. Linux 网络编程: xinetd time
  13. springboot使用zookeeper(curator)实现注册发现与负载均衡
  14. python并发编程之多线程一
  15. git的撤销动作
  16. Css3盒子模型-css学习之旅(5)
  17. 用Laravel Sms实现 laravel短信验证码的发送
  18. Git 切换本地分支 切换远程分支
  19. MATLAB绘图功能(1) 二维高层绘图操作
  20. 树莓派VNC搭建相关教程+Ubuntu16.04连接vncserver灰屏问题!

热门文章

  1. 2020-2021-1 20209307《Linux内核原理与分析》第六周作业
  2. 面试 23-面试技巧 by smyhvae
  3. 多任务-python实现-Thread的基本使用(2.1.1)
  4. Python之word文档替换字符串(也可以用于短模板套用)
  5. Python之excel第三方库xlrd和xlwt
  6. WEBSERVICE 分析器错误信息: 未能创建类型
  7. 【进程/作业管理】篇章一:Linux进程及其管理(系统监控类工具)----glances、dstat
  8. vue3.0自定义指令(drectives)
  9. linux下eclipse
  10. github下载大文件太慢/失败