hiho_1078_线段树区间修改
题目
给定一组数,要求进行若干次操作,这些操作可以分为两种类型:
(1) CMD 1 beg end value 将数组中下标在[beg, end] 区间内数字都变为value
(2) CMD 2 beg end 求出数组中下标在[beg ,end]区间中的所有数字的和
分析
树状数组在区间查询和单点修改情况下效率较线段树高一些,而无法像线段树一样在O(logN)的时间内完成区间修改。因此使用线段树解决。使用线段树主要的是定义好线段树节点的状态。(如代码中注释所说,状态一定要明确,且容易计算!)
实现
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 | #include<iostream> #include<string.h> #include<iostream> #include<queue> #include<cmath> #include<unordered_map> #include<unordered_set> #include<string> #include<vector> using namespace std; const int inf = 1 << 29; const int kMax = 100005; struct Node{ int beg; int end; int val; //若val为非零值,表示当前时刻,节点所代表的区间内所有的值同时被修改为val; //如果为0,一种情况是该节点代表区间内的值同时被修改为val, //一种情况是:该区间内的值没有被同时修改为val(可能从没被修改过,或者之前被同时修改过,但是后来又被修改了其中一部分) int sum; //当前时刻,区间内所有数字的和。这个值就是当前时刻的值,不需要参考value Node(){ val = sum = 0; } }; Node gNodes[4 * kMax]; int weight[kMax]; void BuildTree( int node, int beg, int end){ gNodes[node].beg = beg; gNodes[node].end = end; if (beg == end){ gNodes[node].val = gNodes[node].sum = weight[beg]; //初始化 return ; } int left = 2 * node + 1, right = 2 * node + 2; int mid = (beg + end) / 2; BuildTree(left, beg, mid); BuildTree(right, mid + 1, end); gNodes[node].sum = gNodes[left].sum + gNodes[right].sum; } //从上向下更新 void PushDown( int node){ if (gNodes[node].beg == gNodes[node].end){ //叶子节点处的更新,注意,由于 线段树的节点中的 sum被定义为当前时刻的真实的和。那么, //当叶子节点被修改为了value时,同时将sum给计算出来 gNodes[node].sum = gNodes[node].val; return ; } int left = 2 * node + 1, right = 2 * node + 2; if (gNodes[node].val){ //注意,由于 线段树的节点中的 sum被定义为当前时刻的真实的和。那么,每当pushdown,子节点的value被修改时, //也需要同时将 sum给计算出来! int value = gNodes[node].val; gNodes[left].val = gNodes[right].val = value; gNodes[left].sum = (gNodes[left].end - gNodes[left].beg + 1)*value; gNodes[right].sum = (gNodes[right].end - gNodes[right].beg + 1)*value; } gNodes[node].val = 0; } //从下向上更新 void PushUp( int node){ if (gNodes[node].beg == gNodes[node].end){ gNodes[node].sum = gNodes[node].val; return ; } int left = 2 * node + 1, right = 2 * node + 2; gNodes[node].sum = gNodes[left].sum + gNodes[right].sum; } void Update( int node, int beg, int end, int value){ if (beg == gNodes[node].beg && end == gNodes[node].end){ //对区间进行更新,节点的val 更新为value不用说了。注意由于我们定义的 节点中的sum为当前时刻的真实的和,因此 //需要实时的计算出来 gNodes[node].val = value; gNodes[node].sum = gNodes[node].val*(gNodes[node].end - gNodes[node].beg + 1); return ; } if (beg > end) return ; //查询区间和线段树节点代表的区间不同,则进行区间分解。 需要先将父节点的信息传递给子节点 PushDown(node); int left = 2 * node + 1, right = 2 * node + 2; int mid = (gNodes[node].beg + gNodes[node].end) / 2; if (mid >= end){ Update(left, beg, end, value); } else if (mid < beg){ Update(right, beg, end, value); } else { Update(left, beg, mid, value); Update(right, mid + 1, end, value); } //线段树子节点更新完之后,需要更新父节点的 sum 信息 PushUp(node); } int Query( int node, int beg, int end){ if (gNodes[node].beg == beg && gNodes[node].end == end){ return gNodes[node].sum; } if (beg > end) return 0; PushDown(node); int left = 2 * node + 1, right = 2 * node + 2; int mid = (gNodes[node].beg + gNodes[node].end) / 2; if (mid >= end){ return Query(left, beg, end); } else if (mid < beg){ return Query(right, beg, end); } else { int left_sum = Query(left, beg, mid); int right_sum = Query(right, mid + 1, end); return left_sum + right_sum; } } int main(){ int n; scanf( "%d" , &n); for ( int i = 0; i < n; i++){ scanf( "%d" , &weight[i]); } BuildTree(0, 0, n - 1); scanf( "%d" , &n); int cmd, beg, end, value; for ( int i = 0; i < n; i++){ scanf( "%d" , &cmd); if (cmd == 0){ scanf( "%d %d" , &beg, &end); int result = Query(0, beg - 1, end - 1); printf( "%d\n" , result); } else { scanf( "%d %d %d" , &beg, &end, &value); Update(0, beg - 1, end-1, value); } } return 0; } |
【推荐】还在用 ECharts 开发大屏?试试这款永久免费的开源 BI 工具!
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步