[kuangbin带你飞]专题七 线段树
D - Mayor's posters || 覆盖型线段树 & 离散化
https://vjudge.net/contest/399540#problem/D
对于每个结点,若tree == 0,表示这段区间内颜色不唯一;若tree != 0,这个数字就表示这段区间对应的颜色;
贴n张海报,即n次区间更新update,最终最多能看到n种颜色。1次整个区间查询query。
mark[i] == 1表示能看到第i种颜色,mark[i] == 0表示看不到第i种颜色。
1 <= li <= ri <= 1e7,线段树需要维护的区间过大,数组也要开的很大,会TLE或MLE,需要离散化
1 <= n <= 10000,最多有1e4张海报,最多有2e4个点,所以离散化后的区间为[1, 20000]
#include <cstdio> #include <string> #include <iostream>
#include <algorithm> using namespace std; typedef long long ll; const int maxn=2e5+4; int arr[maxn], _left[maxn], _right[maxn], tree[maxn<<2], lazy[maxn<<2], mark[100005]; void push_down(int node) { if(lazy[node]) { tree[2 * node] = tree[node]; tree[2 * node + 1] = tree[node]; lazy[2 * node] = lazy[node]; lazy[2 * node + 1] = lazy[node]; lazy[node] = 0; } } void query(int node, int l, int r) { if(l == r || tree[node]) { mark[tree[node]] = 1; return; } push_down(node); int mid = (l + r) / 2; query(node * 2, l, mid); query(node * 2 + 1, mid + 1, r); } void update(int node, int l, int r, int x, int y, ll c) { if(x <= l && y >= r) { tree[node] = c; lazy[node] = c; return; } push_down(node); int mid = (l + r) / 2; if(x <= mid) update(node * 2, l, mid, x, y, c); if(y > mid) update(node * 2 + 1, mid + 1, r, x, y, c); if(tree[node*2] == tree[node*2+1]) tree[node] = tree[node*2]; else tree[node] = 0; } int main() { int n, m, x, y, t; scanf("%d", &t); while(t--) { scanf("%d", &n); fill(mark + 1, mark + 1 + n, 0); for(int i = 1; i <= n; i++) { scanf("%d %d", &_left[i], &_right[i]); arr[i*2-1] = _left[i], arr[i*2] = _right[i]; } sort(arr + 1, arr + 1 + 2 * n); int cnt = unique(arr + 1, arr + 1 + 2 * n) - (arr + 1); fill(tree + 1, tree + 1 + cnt * 4, 0); fill(lazy + 1, lazy + 1 + cnt * 4, 0); for(int i = 1; i <= n; ++i) { int x = lower_bound(arr + 1, arr + 1 + cnt, _left[i]) - arr; int y = lower_bound(arr + 1, arr + 1 + cnt, _right[i]) - arr; update(1, 1, cnt, x, y, i); } query(1, 1, cnt); int ans = 0; for(int i = 1; i <= n; i++) ans += mark[i]; printf("%d\n", ans); } }
H - Can you answer these queries?
https://vjudge.net/contest/399540#problem/H
#include <cstdio> #include <cstring> #include <algorithm> #include <cmath> using namespace std; typedef long long ll; const int maxn = 1e5 + 4; ll arr[maxn], tree[maxn<<2], lazy[maxn<<2]; bool mark[maxn<<2]; void build(int node, int l, int r) { if(l == r) {tree[node] = arr[l]; return;} int mid = (l + r) / 2; build(node * 2, l, mid); build(node * 2 + 1, mid + 1, r); tree[node] = tree[node * 2] + tree[node * 2 + 1]; } ll query(int node, int l, int r, int x, int y) { if(x <= l && y >= r) return tree[node]; ll ans = 0; int mid = (l + r) / 2; if(x <= mid) ans += query(node * 2, l, mid, x, y); if(y > mid) ans += query(node * 2 + 1, mid + 1, r, x, y); return ans; } void update(int node, int l, int r, int x, int y) { if(l == r) { tree[node] = (ll)sqrt(tree[node]); if(tree[node] == 1) mark[node] = 1; return; } if(mark[node] == 1) return; int mid = (l + r) / 2; if(x <= mid) update(node * 2, l, mid, x, y); if(y > mid) update(node * 2 + 1, mid + 1, r, x, y); tree[node] = tree[node * 2] + tree[node * 2 + 1]; mark[node] = mark[node * 2] && mark[node * 2 + 1]; } int main() { int n, m, d, x, y; int q = 1; while(~scanf("%d", &n)) { memset(mark, 0, sizeof(mark)); printf("Case #%d:\n", q); for(int i = 1; i <= n; ++i) scanf("%lld", &arr[i]); build(1, 1, n); scanf("%d", &m); for(int i = 0; i < m; ++i) { scanf("%d %d %d", &d, &x, &y); if(x > y) swap(x, y); if(d) printf("%lld\n", query(1, 1, n, x, y)); else update(1, 1, n, x, y); } fill(tree + 1, tree + 1 + 4 * n, 0); fill(lazy + 1, lazy + 1 + 4 * n, 0); ++q; printf("\n"); } }
J - Assign the task || 覆盖型线段树 & dfs序
https://vjudge.net/contest/399540#problem/J
多组数据vector清空!!!
用dfs序转化成区间,dfs序就是arr,对arr的连续区间操作使用线段树
L[x], R[x]表示x节点对应的区间左端和右端,相当于arr的下标(虽然这道题arr没用
注意题目中分配的任务可以为0,所以tree和lazy应该初始化为-1
eg.
2
/ \
3 5
/ \
4 1
L[2] = 1, R[2] = 5;
L[3] = 2, R[3] = 4;
L[4] = 3, R[4] = 3;
L[1] = 4, R[1] = 4;
L[5] = 5, R[5] = 5;
1 2 3 4 5
2 3 4 1 5
#include <cstdio> #include <vector> using namespace std; const int maxn = 5e4 + 3; typedef long long ll; ll tree[maxn<<2], lazy[maxn<<2]; vector<int> G[maxn]; bool boss[maxn]; int cur; int L[maxn], R[maxn]; void dfs(int x) { L[x] = ++cur; for(int i = 0; i < G[x].size(); ++i) { dfs(G[x][i]); } R[x] = cur; } void push_down(int node) { if(lazy[node] != -1) { tree[2 * node] = lazy[node]; tree[2 * node + 1] = lazy[node]; lazy[2 * node] = lazy[node]; lazy[2 * node + 1] = lazy[node]; lazy[node] = -1; } } ll query(int node, int l, int r, int x, int y) { if(x <= l && y >= r) return tree[node]; push_down(node); ll ans = 0L; int mid = (l + r) / 2; if(x <= mid) ans = query(node * 2, l, mid, x, y); if(y > mid) ans = query(node * 2 + 1, mid + 1, r, x, y); return ans; } void update(int node, int l, int r, int x, int y, ll c) { if(x <= l && y >= r) { tree[node] = c; lazy[node] = c; return; } push_down(node); int mid = (l + r) / 2; if(x <= mid) update(node * 2, l, mid, x, y, c); if(y > mid) update(node * 2 + 1, mid + 1, r, x, y, c); if(tree[node*2] == tree[node*2+1]) tree[node] = tree[node * 2]; else tree[node] = -1; } int main() { int t; scanf("%d", &t); for(int q = 1; q <= t; ++q) { printf("Case #%d:\n", q); cur = 0; int n, x, y, m; char c; scanf("%d", &n); fill(boss + 1, boss + 1 + n, 0); for(int i = 0; i < n-1; ++i) { scanf("%d %d", &x, &y); G[y].push_back(x); boss[x] = 1; } int root; fill(lazy + 1, lazy + 1 + 4 * n, -1); fill(tree + 1, tree + 1 + 4 * n, -1); for(int i = 1; i <= n; ++i) { if(!boss[i])//找到根节点 { root = i; break; } } scanf("%d", &m); dfs(root); for(int i = 0; i < m; ++i) { scanf(" %c", &c); if(c =='C') { scanf("%d", &x); printf("%lld\n", query(1, 1, n, L[x], L[x])); } else { scanf("%d %d", &x, &y); update(1, 1, n, L[x], R[x], y); } } for(int i = 1; i <= n; ++i) G[i].clear();//一直MLE啊啊啊啊啊啊啊 } }