线段树的成段更新,需要用到延迟标记
就是每次更新的时候不要更新到底,用延迟标记使得更新延迟到下次需要更新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; }
这题比上面那道的操作稍微复杂了一点,把某个区间的数统一加上某个值。
#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; }
然后更神的是这道题可以用并查集做
从acmol的空间看的http://blog.acmol.com/?p=751
/* ID: sdj22251 PROG: inflate LANG: C++ */ #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 9*9*9*9 #define INF 1000000000 using namespace std; int hash[10000005]; int father[40005]; int a[10005], b[10005], x[20005]; bool v[40005]; int find(int x) { if(father[x] == -1) return x; int t = find(father[x]); father[x] = t; return t; } int main() { int T, n; scanf("%d", &T); while(T--) { scanf("%d", &n); for(int i = 0; i < n; i++) { scanf("%d%d", &a[i], &b[i]); x[2 * i] = a[i]; x[2 * i + 1] = b[i]; } sort(x, x + 2 * n); int cnt = unique(x, x + 2 * n) - x; hash[x[0]] = 0; for(int i = 1; i < cnt; i++) { int flag = 0; if(x[i - 1] + 1 != x[i]) flag = 1; hash[x[i]] = hash[x[i - 1]] + flag + 1; } int ans = 0; memset(v, 0, sizeof(v)); memset(father, -1, sizeof(father)); for(int i = n - 1; i >= 0; i--) { bool flag = false; int fa = find(hash[a[i]]), fb; for(int j = hash[b[i]]; j >= hash[a[i]]; j = fb - 1) { fb = find(j); if(!v[fb]) v[fb] = flag = true; if(fa != fb) father[fb] = fa; } if(flag) ans++; } 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; }