首页 > 其他 > 详细

树——线段树区间修改

时间:2015-10-07 10:52:29      阅读:334      评论:0      收藏:0      [点我收藏+]

上两篇博文简单说了线段树,线段树节点修改非常简单,不过区间修改有一定难度,不过也是线段树中的简单环节,接下来看一个实例。

#1078 : 线段树的区间修改

时间限制:10000ms

单点时限:1000ms

内存限制:256MB

描述

对于小Ho表现出的对线段树的理解,小Hi表示挺满意的,但是满意就够了么?于是小Hi将问题改了改,又出给了小Ho:

假设货架上从左到右摆放了N种商品,并且依次标号为1到N,其中标号为i的商品的价格为Pi。小Hi的每次操作分为两种可能,第一种是修改价格——小Hi给出一段区间[L, R]和一个新的价格NewP,所有标号在这段区间中的商品的价格都变成NewP。第二种操作是询问——小Hi给出一段区间[L, R],而小Ho要做的便是计算出所有标号在这段区间中的商品的总价格,然后告诉小Hi。

那么这样的一个问题,小Ho该如何解决呢?

提示:推动科学发展的除了人的好奇心之外还有人的懒惰心!

输入

每个测试点(输入文件)有且仅有一组测试数据。

每组测试数据的第1行为一个整数N,意义如前文所述。

每组测试数据的第2行为N个整数,分别描述每种商品的重量,其中第i个整数表示标号为i的商品的重量Pi。

每组测试数据的第3行为一个整数Q,表示小Hi进行的操作数。

每组测试数据的第N+4~N+Q+3行,每行分别描述一次操作,每行的开头均为一个属于0或1的数字,分别表示该行描述一个询问和一次商品的价格的更改两种情况。对于第N+i+3行,如果该行描述一个询问,则接下来为两个整数Li, Ri,表示小Hi询问的一个区间[Li, Ri];如果该行描述一次商品的价格的更改,则接下来为三个整数Li,Ri,NewP,表示标号在区间[Li, Ri]的商品的价格全部修改为NewP。

对于100%的数据,满足N<=10^5,Q<=10^5, 1<=Li<=Ri<=N,1<=Pi<=N, 0<Pi, NewP<=10^4。

输出

对于每组测试数据,对于每个小Hi的询问,按照在输入中出现的顺序,各输出一行,表示查询的结果:标号在区间[Li, Ri]中的所有商品的价格之和。

  • 样例输入

  • 10
    4733 6570 8363 7391 4511 1433 2281 187 5166 378 
    6
    1 5 10 1577
    1 1 7 3649
    0 8 10
    0 1 4
    1 6 8 157
    1 3 4 1557
  • 样例输出

  • 4731
    14596


AC代码:线段树区间修改,区间求和,在线段树节点修改的基础上加一个value记录标记。

#include<iostream>

#include<cstdio>

#include<cstdlib>

#include<algorithm>

#include<vector>

#include<list>

#include<iterator>

#include<string>

#include<stack>

using namespace std;

const int MAX = 100000100;


struct NODE {

int value, left, right, sum;

}node[MAX];


void BuildTree(int n, int left, int right) {

node[n].left = left;

node[n].right = right;

node[n].value = 0;

if (left == right)

{

scanf("%d", &node[n].sum);

return;

}

int mid = (left + right) >> 1;

BuildTree(n << 1, left, mid);

BuildTree((n << 1) | 1, mid + 1, right);

node[n].sum = node[n << 1].sum + node[(n << 1) | 1].sum;

}


void PushDown(int n) {

if (node[n].value){

node[n << 1].sum = (node[n << 1].right - node[n << 1].left + 1)*node[n].value;

node[n << 1 | 1].sum = (node[n << 1 | 1].right - node[n << 1 | 1].left + 1)*node[n].value;

node[n << 1].value = node[n << 1 | 1].value = node[n].value;

node[n].value = 0;

}

}


int FindTree(int n, int begin, int end) {

int p1 = 0,p2 = 0;

if (node[n].left >= begin&&node[n].right <= end)

return node[n].sum;

PushDown(n);

if (begin <= node[n << 1].right)

p1 = FindTree(n << 1, begin, end);

if (end >= node[(n << 1) | 1].left)

p2 = FindTree((n << 1) | 1, begin, end);

node[n].sum = node[n << 1].sum + node[n << 1 | 1].sum;

return p1 + p2;

}


void UpdateTree(int n, int left, int right, int val) {

if (node[n].left >= left && node[n].right <= right)

{

node[n].sum = (node[n].right - node[n].left + 1)*val;

node[n].value = val;

return;

}

PushDown(n);

if (left <= node[n << 1].right)

UpdateTree(n << 1, left,right,val);

if (right >= node[(n << 1) | 1].left)

UpdateTree((n << 1) | 1,left,right,val);

node[n].sum = node[n << 1].sum + node[(n << 1) | 1].sum;


}


int main()

{

int N;

int m;

int s, l, r, v;

while (~scanf("%d", &N))

{

BuildTree(1, 0, N - 1);

scanf("%d", &m);

for (int i = 0; i < m; i++)

{

scanf("%d %d %d", &s, &l, &r);

if (s == 0)

printf("%d\n", FindTree(1, l - 1, r - 1));

if (s == 1)

{

scanf("%d", &v);

UpdateTree(1, l - 1, r -1,v);

}

}

}

return 0;

}


本文出自 “风雪夜之星” 博客,请务必保留此出处http://592669550.blog.51cto.com/5487419/1700560

树——线段树区间修改

原文:http://592669550.blog.51cto.com/5487419/1700560

(0)
(0)
   
举报
评论 一句话评论(0
关于我们 - 联系我们 - 留言反馈 - 联系我们:wmxa8@hotmail.com
© 2014 bubuko.com 版权所有
打开技术之扣,分享程序人生!