线段树几题 --------- 成段更新

本文详细介绍了线段树的成段更新方法,使用延迟标记避免复杂度退化为O(n),并提供了几个具体应用实例,包括统一区间数值、区间涂色等操作,以及如何利用线段树解决实际问题。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

线段树的成段更新,需要用到延迟标记

就是每次更新的时候不要更新到底,用延迟标记使得更新延迟到下次需要更新or询问到的时候

否则就会退化到O(n)的复杂度

1.hdu 1698 Just a Hook

大意是每次把某一段所有数的值改变成某个值,最后求总和。


#include <iostream> #include <vector> #include <list> #include <map> #include <set> #include <deque> #include <queue> #include <stack> #include <bitset> #include <algorithm> #include <functional> #include <numeric> #include <utility> #include <sstream> #include <iomanip> #include <cstdio> #include <cmath> #include <cstdlib> #include <cctype> #include <string> #include <cstring> #include <cmath> #include <ctime> #define MAXN 100005 #define INF 100000000 #define eps 1e-11 #define L(x) x<<1 #define R(x) x<<1|1 using namespace std; struct node { int left, right, mid; int cover, len, sum; }tree[4 * MAXN]; void make_tree(int s, int e, int C) { tree[C].left = s; tree[C].right = e; tree[C].mid = (s + e) / 2; tree[C].len = tree[C].right - tree[C].left + 1; tree[C].cover = 1; tree[C].sum = tree[C].cover * tree[C].len; if(s == e) return; make_tree(s, tree[C].mid, L(C)); make_tree(tree[C].mid + 1, e, R(C)); } void up(int C) { tree[C].sum = tree[L(C)].sum + tree[R(C)].sum; } void down(int C) { if(tree[C].cover) { tree[L(C)].cover = tree[R(C)].cover = tree[C].cover; tree[L(C)].sum = tree[L(C)].len * tree[L(C)].cover; tree[R(C)].sum = tree[R(C)].len * tree[R(C)].cover; tree[C].cover = 0; } } void update(int s, int e, int k, int C) { if(tree[C].left >= s && tree[C].right <= e) { tree[C].cover = k; tree[C].sum = tree[C].cover * tree[C].len; return; } down(C); if(tree[C].mid < s) update(s, e, k, R(C)); else if(tree[C].mid >= e) update(s, e, k, L(C)); else { update(s, tree[C].mid, k, L(C)); update(tree[C].mid + 1, e, k, R(C)); } up(C); } int main() { //freopen("d:/data.in","r",stdin); //freopen("d:/data.out","w",stdout); int t, n, i, x, y, z, cas = 0, m; scanf("%d", &t); while(t--) { scanf("%d", &n); make_tree(1, n, 1); scanf("%d", &m); for(i = 0; i < m; i++) { scanf("%d%d%d", &x, &y, &z); update(x, y, z, 1); } printf("Case %d: The total value of the hook is %d.\n", ++cas, tree[1].sum); } return 0; }
2. POJ 3468A Simple Problem with Integers


这题比上面那道的操作稍微复杂了一点,把某个区间的数统一加上某个值。


#include <iostream> #include <vector> #include <list> #include <map> #include <set> #include <deque> #include <queue> #include <stack> #include <bitset> #include <algorithm> #include <functional> #include <numeric> #include <utility> #include <sstream> #include <iomanip> #include <cstdio> #include <cmath> #include <cstdlib> #include <cctype> #include <string> #include <cstring> #include <cmath> #include <ctime> #define MAXN 100005 #define INF 100000000 #define eps 1e-11 #define L(x) x<<1 #define R(x) x<<1|1 using namespace std; struct node { int left, right, mid; __int64 cover, len; __int64 sum; }tree[4 * MAXN]; __int64 a[100005]; void up(int C) { tree[C].sum = tree[L(C)].sum + tree[R(C)].sum; } void down(int C) { if(tree[C].cover) { tree[L(C)].cover += tree[C].cover; tree[R(C)].cover += tree[C].cover; tree[L(C)].sum += tree[C].cover * tree[L(C)].len; tree[R(C)].sum += tree[C].cover * tree[R(C)].len; tree[C].cover = 0; } } void make_tree(int s, int e, int C) { tree[C].left = s; tree[C].right = e; tree[C].mid = (s + e) / 2; tree[C].cover = 0; tree[C].sum = 0; tree[C].len = tree[C].right - tree[C].left + 1; if(s == e) { tree[C].sum = a[s]; return; } make_tree(s, tree[C].mid, L(C)); make_tree(tree[C].mid + 1, e, R(C)); up(C); } void update(int s, int e, __int64 k, int C) { if(tree[C].left >= s && tree[C].right <= e) { tree[C].cover += k; tree[C].sum += k * tree[C].len; return; } down(C); if(tree[C].mid < s) update(s, e, k, R(C)); else if(tree[C].mid >= e) update(s, e, k, L(C)); else { update(s, tree[C].mid, k, L(C)); update(tree[C].mid + 1, e, k, R(C)); } up(C); } __int64 query(int s, int e, int C) { if(tree[C].left >= s && tree[C].right <= e) return tree[C].sum; down(C); __int64 tmp = 0; if(tree[C].mid < s) tmp += query(s, e, R(C)); else if(tree[C].mid >= e) tmp += query(s, e, L(C)); else { tmp += query(s, tree[C].mid, L(C)); tmp += query(tree[C].mid + 1, e, R(C)); } return tmp; } int main() { //freopen("d:/data.in","r",stdin); //freopen("d:/data.out","w",stdout); int n, m, i, x, y; __int64 z; char s[5]; scanf("%d%d", &n, &m); for(i = 1; i <= n; i++) scanf("%I64d", &a[i]); make_tree(1, n, 1); while(m--) { scanf("%s", s); if(s[0] == 'Q') { scanf("%d%d", &x, &y); printf("%I64d\n",query(x, y, 1)); } else if(s[0] == 'C') { scanf("%d%d%I64d", &x, &y, &z); update(x, y, z, 1); } } return 0; }

3.poj 2528 Mayor’s posters

大意就是往墙上按区间涂色,看最后能看见的颜色个数

比较麻烦的就是离散化的事情,先把所有的坐标存下来,去重后映射一下,这时就有些问题了,比如原始坐标是1, 3, 6, 10,映射完了是0, 1, 2, 3,3和6本来中间还有几块的,离散完了成相邻的了,所以这里就要处理一下,1,3,6, 10就要处理成1,2,3,4,6,7,10之类的,总之相邻的坐标之差如果大于1了,就在中间添加一个适当的数表示这之间还有块。

然后就建线段树,查询的时候查整个线段树中颜色的个数就行了。

#include <iostream> #include <vector> #include <list> #include <map> #include <set> #include <deque> #include <queue> #include <stack> #include <bitset> #include <algorithm> #include <functional> #include <numeric> #include <utility> #include <sstream> #include <iomanip> #include <cstdio> #include <cmath> #include <cstdlib> #include <cctype> #include <string> #include <cstring> #include <cmath> #include <ctime> #define MAXN 10005 #define INF 100000000 #define eps 1e-11 #define L(x) x<<1 #define R(x) x<<1|1 using namespace std; struct node { int left, right, mid; int cover; }tree[16 * MAXN]; int a[4 * MAXN]; int l[MAXN]; int r[MAXN]; int ans, n; bool used[MAXN]; void make_tree(int s, int e, int C) { tree[C].left = s; tree[C].right = e; tree[C].cover = -1; tree[C].mid = (s + e) / 2; if(s == e) return; make_tree(s, tree[C].mid, L(C)); make_tree(tree[C].mid + 1, e, R(C)); } void down(int C) { if(tree[C].cover != -1) { tree[L(C)].cover = tree[R(C)].cover = tree[C].cover; tree[C].cover = -1; } } void update(int s, int e, int k, int C) { if(tree[C].left >= s && tree[C].right <= e) { tree[C].cover = k; return; } down(C); if(tree[C].mid < s) update(s, e, k, R(C)); else if(tree[C].mid >= e) update(s, e, k, L(C)); else { update(s, tree[C].mid, k, L(C)); update(tree[C].mid + 1, e, k, R(C)); } } void query(int C) { if(tree[C].cover != -1) { if(!used[tree[C].cover]) { ans++; used[tree[C].cover] = 1; } return; } if(tree[C].left == tree[C].right) return; query(L(C)); query(R(C)); } int b_search(int v) { int left = 0, right = n - 1; while(left <= right) { int mid = (left + right) / 2; if(a[mid] == v) return mid; else if(a[mid] > v) right = mid - 1; else left = mid + 1; } return 0; } int main() { //freopen("d:/data.in","r",stdin); //freopen("d:/data.out","w",stdout); int t, m, i; scanf("%d", &t); while(t--) { ans = 0; memset(used, 0, sizeof(used)); scanf("%d", &m); int cnt = 0; for(i = 0; i < m; i++) { scanf("%d%d", &l[i], &r[i]); a[cnt++] = l[i]; a[cnt++] = r[i]; } sort(a, a + cnt); n = unique(a, a + cnt) - a; for(i = n - 1; i > 0; i--) { if(a[i] - a[i - 1] != 1) a[n++] = a[i - 1] + 1; } sort(a, a + n); n = unique(a, a + n) - a; make_tree(0, n - 1, 1); for(i = 0; i < m; i++) { int ll = b_search(l[i]); //printf("ll %d\n", ll); int rr = b_search(r[i]); update(ll, rr, i, 1); //printf("rr %d\n", rr); } query(1); printf("%d\n", ans); } return 0; }

4.POJ 2777 Count Color

几乎与2528一摸一样的题,只不过更加裸了


#include <iostream> #include <vector> #include <list> #include <map> #include <set> #include <deque> #include <queue> #include <stack> #include <bitset> #include <algorithm> #include <functional> #include <numeric> #include <utility> #include <sstream> #include <iomanip> #include <cstdio> #include <cmath> #include <cstdlib> #include <cctype> #include <string> #include <cstring> #include <cmath> #include <ctime> #define MAXN 100005 #define INF 100000000 #define eps 1e-11 #define L(x) x<<1 #define R(x) x<<1|1 using namespace std; struct node { int left, right, mid; int cover; }tree[4 * MAXN]; bool used[33]; int ans; void make_tree(int s, int e, int C) { tree[C].left = s; tree[C].right = e; tree[C].cover = 1; tree[C].mid = (s + e) / 2; if(s == e) return; make_tree(s, tree[C].mid, L(C)); make_tree(tree[C].mid + 1, e, R(C)); } void down(int C) { if(tree[C].cover != -1) { tree[L(C)].cover = tree[R(C)].cover = tree[C].cover; tree[C].cover = -1; } } void update(int s, int e, int k, int C) { if(tree[C].left >= s && tree[C].right <= e) { tree[C].cover = k; return; } down(C); if(tree[C].mid < s) update(s, e, k, R(C)); else if(tree[C].mid >= e) update(s, e, k, L(C)); else { update(s, tree[C].mid, k, L(C)); update(tree[C].mid + 1, e, k, R(C)); } } void query(int s, int e, int C) { if(tree[C].cover != -1) { if(!used[tree[C].cover]) { ans++; used[tree[C].cover] = 1; } return; } if(tree[C].left == tree[C].right) return; if(tree[C].mid < s) query(s, e, R(C)); else if(tree[C].mid >= e) query(s, e, L(C)); else { query(s, tree[C].mid, L(C)); query(tree[C].mid + 1, e, R(C)); } } int main() { //freopen("d:/data.in","r",stdin); //freopen("d:/data.out","w",stdout); int n, m, t, x, y, z, i; char s[5]; scanf("%d%d%d", &n, &m, &t); make_tree(1, n, 1); while(t--) { scanf("%s", s); if(s[0] == 'C') { scanf("%d%d%d", &x, &y, &z); if(x > y) swap(x, y); update(x, y, z, 1); } else { scanf("%d%d", &x, &y); ans = 0; memset(used, 0, sizeof(used)); query(x, y, 1); printf("%d\n", ans); } } return 0; }

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值