hdu 1556 涂气球 线段树(区间更新~对区间[x,y]更新,求任意节点被更新的次数)
Color the ball
Time Limit: 9000/3000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)
Total Submission(s): 29526 Accepted Submission(s): 14356
Problem Description
N个气球排成一排,从左到右依次编号为1,2,3....N.每次给定2个整数a
b(a <=
b),lele便为骑上他的“小飞鸽"牌电动车从气球a开始到气球b依次给每个气球涂一次颜色。但是N次以后lele已经忘记了第I个气球已经涂过几次颜色了,你能帮他算出每个气球被涂过几次颜色吗?
Input
每个测试实例第一行为一个整数N,(N <= 100000).接下来的N行,每行包括2个整数a b(1 <= a <= b <= N)。
当N = 0,输入结束。
当N = 0,输入结束。
Output
每个测试实例输出一行,包括N个整数,第I个数代表第I个气球总共被涂色的次数。
Sample Input
3
1 1
2 2
3 3
3
1 1
1 2
1 3
0
Sample Output
1 1 1
3 2 1
//注意laz[]要和线段树数组开一样大小 #include<iostream> #include<algorithm> #include<vector> #include<math.h> #include<stdio.h> #include<string.h> #include<algorithm> const int n = 100050; using namespace std; void pushdown(int num); int tre[n * 4]; int laz[n*4]; void update(int num, int le, int ri, int x, int y,int z) { if (x <= le && y >= ri) { tre[num] = tre[num] + z;//初值为0,z=1 laz[num] = laz[num] + z; return; } pushdown(num); int mid = (le + ri) / 2; if (x <= mid) update(num * 2, le, mid, x, y, z); if (y > mid) update(num * 2 + 1, mid + 1, ri, x, y, z); } void pushdown(int num) { if (laz[num] != 0) { tre[num * 2] += laz[num]; tre[num * 2 + 1] += laz[num]; laz[num * 2] += laz[num]; laz[num * 2 + 1] += laz[num]; laz[num] = 0; } } int query(int num, int le, int ri, int x) { if (le == ri) { return tre[num]; } pushdown(num); int mid = (le + ri) / 2; if (x <= mid) return query(num * 2, le, mid, x); else return query(num * 2 + 1, mid + 1, ri, x); } int main() { int t; while (cin >> t) { memset(tre, 0, sizeof(tre)); memset(laz, 0, sizeof(laz));//初始化延迟标记 for (int i = 0; i < t; i++) { int x, y; cin >> x >> y; update(1, 1, t, x, y, 1); cout << query(1, 1, n, x) << endl; } } return 0; }
用结构体储存数据
#include <stdio.h> #include<iostream> #include <string.h> using namespace std; struct node { int left, right, count; }c[100005 * 3]; int sum[100005]; void build(int le, int ri, int root) { c[root].left = le; c[root].right = ri; c[root].count = 0; if (le == ri) return; int mid = (le + ri) / 2; build(le, mid, root * 2); build(mid + 1, ri, root * 2 + 1); } void update(int le, int ri, int root)//更新 { if (c[root].left == le && c[root].right == ri)//只需要在这个区间+1就行了,节省时间,不用找到每个数 { c[root].count++; return; } int mid = (c[root].left + c[root].right) / 2; if (mid<le)//如果更新区间在右子树上,就只更新右区间 update(le, ri, root * 2 + 1); else if (mid >= ri)//更新左子树 update(le, ri, root * 2); else//更新区间即在右子树上,又在左子树上 { update(le, mid, root * 2); update(mid + 1, ri, root * 2 + 1); } } void tosum(int root)//求和、记录每个气球被涂过的次数 { for (int i = c[root].left; i <= c[root].right; i++) sum[i] += c[root].count; if (c[root].left == c[root].right) return; tosum(root * 2);//通过子节点来更新父节点 tosum(root * 2 + 1); } int main() { int n; while (scanf("%d", &n) && n) { memset(sum, 0, sizeof(sum)); memset(&c, 0, sizeof(&c)); build(1, n, 1); for (int i = 0; i<n; i++) { int le, ri; scanf("%d %d", &le, &ri); update(le, ri, 1); } tosum(1); printf("%d", sum[1]); for (int i = 2; i <= n; i++) printf(" %d", sum[i]); printf("\n"); } return 0; }
等风起的那一天,我已准备好一切