kuangbin专题七:线段树
终于到专题七了。
思路:线段树模板题。
#include<iostream> #include<cstdio> #include<algorithm> #include<cstring> #include<cmath> using namespace std; const int maxn = 5e4 + 5; int val[maxn]; struct Node{ int l, r, val; } node[maxn * 4]; void pushup(int idx){ node[idx].val = node[idx << 1].val + node[idx << 1 | 1].val; } void build(int l, int r, int idx){ if(l >= r){ node[idx] = {l, r, val[l]}; } else{ int mid = (l + r) >> 1; node[idx] = {l, r, 0}; build(l, mid, idx << 1), build(mid + 1, r, idx << 1 | 1); pushup(idx); } } void update(int pos, int val, int idx){ if(node[idx].r == node[idx].l && node[idx].l == pos){ node[idx].val += val; } else{ int mid = (node[idx].l + node[idx].r) >> 1; if(pos <= mid) update(pos, val, idx << 1); else update(pos, val, idx << 1 | 1); pushup(idx); } } int query(int l, int r, int idx){ if(l <= node[idx].l && node[idx].r <= r) return node[idx].val; int res = 0; int mid = (node[idx].l + node[idx].r) >> 1; if(l <= mid) res += query(l, r, idx << 1); if(r > mid) res += query(l, r, idx << 1 | 1); return res; } int main(){ int T; scanf("%d", &T); for(int t = 1; t <= T; t++){ printf("Case %d:\n", t); int n; scanf("%d", &n); for(int i = 1; i <= n; i++) scanf("%d", &val[i]); build(1, n, 1); string op; while(cin >> op && op != "End"){ int l, r; scanf("%d%d", &l, &r); if(op == "Query") printf("%d\n", query(l, r, 1)); else if(op == "Add") update(l, r, 1); else update(l, -r, 1); } } return 0; }
思路:模板题。
#include<iostream> #include<cstdio> #include<algorithm> #include<cstring> #include<cmath> using namespace std; const int maxn = 2e5 + 5; int score[maxn], maxScore[maxn * 4]; void pushup(int idx){ maxScore[idx] = max(maxScore[idx<<1], maxScore[idx<<1|1]); } void build(int idx, int l, int r){ if(l == r){ maxScore[idx] = score[l]; return; } int mid = (l + r) >> 1; build(idx << 1, l, mid), build(idx << 1 | 1, mid + 1, r); pushup(idx); } void update(int idx, int l, int r, int x, int v){ if(l == r){ maxScore[idx] = v; return; } int mid = (l + r) >> 1; if(x <= mid) update(idx << 1, l, mid, x, v); else update(idx << 1 | 1, mid + 1, r, x, v); pushup(idx); } int query(int idx, int l, int r, int x, int y){ if(x <= l && r <= y) return maxScore[idx]; int mid = (l + r) >> 1, ans = -1; if(x <= mid) ans = max(ans, query(idx << 1, l, mid, x, y)); if(mid < y) ans = max(ans, query(idx << 1 | 1, mid + 1, r, x, y)); return ans; } int main(){ int n, m; while(scanf("%d%d", &n, &m) != EOF){ for(int i = 1; i <= n; i++) scanf("%d", &score[i]); build(1, 1, n); char op; int A, B; while(m--){ scanf(" %c%d%d", &op, &A, &B); if(op == 'Q') printf("%d\n", query(1, 1, n, A, B)); else update(1, 1, n, A, B); } } return 0; }
POJ3468 A Simple Problem with Integers
思路:模板题,注意push down。
#include <iostream> #include <stdio.h> using namespace std; const int MAXN = 1e5 + 10; long long sum[MAXN << 2]; long long w[MAXN << 2]; void push_up(int idx){ sum[idx] = sum[idx << 1] + sum[idx << 1 | 1]; } void push_down(int idx, int m){ if(w[idx]){ w[idx << 1] += w[idx]; w[idx << 1 | 1] += w[idx]; sum[idx << 1] += (m - (m >> 1)) * w[idx]; sum[idx << 1 | 1] += (m >> 1) * w[idx]; w[idx] = 0; } } void build(int idx, int l, int r){ w[idx] = 0; if(l == r){ scanf("%lld", &sum[idx]); return; } int mid = (l + r) >> 1; build(idx << 1, l, mid); build(idx << 1 | 1, mid + 1, r); push_up(idx); } void update(int idx, int l, int r, int L, int R, long long value){ if(L <= l && R >= r){ sum[idx] += (r - l + 1) * value; w[idx] += value; return; } push_down(idx, r - l + 1); int mid = (l + r) >> 1; if(L <= mid) update(idx << 1, l, mid, L, R, value); if(R > mid) update(idx << 1 | 1, mid + 1, r, L, R, value); push_up(idx); } long long query(int idx, int l, int r, int L, int R){ if(L <= l && R >= r) return sum[idx]; push_down(idx, r - l + 1); int mid = (l + r) >> 1; long long ans = 0; if(L <= mid) ans += query(idx << 1, l, mid, L, R); if(R > mid) ans += query(idx << 1 | 1, mid + 1, r, L, R); return ans; } int main(){ int n, m; scanf("%d%d", &n, &m); build(1, 1, n); while(m--){ char str[3]; int x, y; long long z; scanf("%s", str); if(str[0] == 'C'){ scanf("%d%d%lld", &x, &y, &z); update(1, 1, n, x, y, z); }else{ scanf("%d%d", &x, &y); printf("%lld\n", query(1, 1, n, x, y)); } } }
思路:乱七八糟的题目,乱七八糟的解法。自己的代码一直WA,对着以前抄的AC代码也WA。。。。把以前代码贴上。
#include<iostream> #include<cstring> #include<cstdio> #include<algorithm> #include<stack> #include<cmath> using namespace std; #define INF 0x3f3f3f3f const int maxn = 10000 + 5; int n, t; int vis[maxn<<3], sum[maxn<<4]; int li[maxn<<1], ri[maxn<<1], lsh[maxn<<2]; void pushdown(int rt){ sum[rt<<1] = sum[rt]; sum[rt<<1|1] = sum[rt]; sum[rt] = -1; } void update(int L, int R, int C, int l, int r, int rt){ if(L<=l && r<=R){ sum[rt] = C; return; } if(sum[rt]!=-1) pushdown(rt); int m = (l+r)>>1; if(m>=R) update(L, R, C, l, m, rt<<1); else if(L > m) update(L, R, C, m+1, r, rt<<1|1); else update(L, m, C, l, m, rt<<1), update(m+1, R, C, m+1, r, rt<<1|1); } int ans; void query(int l, int r, int rt){ if(!vis[sum[rt]]&&sum[rt]!=-1){ ans++; vis[sum[rt]] = 1; return; } if(l == r) return; if(sum[rt] != -1) pushdown(rt); int m = (l+r) >> 1; query(l, m, rt<<1); query(m+1, r, rt<<1|1); } int main(){ scanf("%d", &t); while(t--){ scanf("%d", &n); memset(sum, -1, sizeof(sum)); memset(vis, 0, sizeof(sum)); int tot = 0; for(int i = 0; i < n; i++){ scanf("%d%d", &li[i], &ri[i]); lsh[tot++] = li[i]; lsh[tot++] = ri[i]; } sort(lsh, lsh+tot); int mm = unique(lsh, lsh+tot) - lsh; int tt = mm; for(int i = 1; i < tt; i++) if(lsh[i]-lsh[i-1] > 1) lsh[mm++] = lsh[i-1]+1; sort(lsh, lsh+mm); for(int i = 0; i < n; i++){ int x = lower_bound(lsh, lsh+mm, li[i]) - lsh; int y = lower_bound(lsh, lsh+mm, ri[i]) - lsh; update(x, y, i, 0, mm-1, 1); } ans = 0; query(0, mm-1, 1); printf("%d\n", ans); } return 0; }
思路:模板题。
#include<iostream> #include<cstdio> #include<cstring> #include<algorithm> using namespace std; const int maxn = 1e5 + 5; int tree[maxn << 2]; void build(int idx, int l, int r){ if(l == r){ tree[idx] = 1; return; } int mid = (l + r) >> 1; build(idx << 1, l, mid); build(idx << 1 | 1, mid + 1, r); tree[idx] = 1; } void pushdown(int idx){ tree[idx << 1] = tree[idx << 1 | 1] = tree[idx]; } void update(int idx, int l, int r, int L, int R, int meta){ if(L <= l && r <= R){ tree[idx] = meta; return; } if(tree[idx] != -1) pushdown(idx); int mid = (l + r) >> 1; if(L <= mid) update(idx << 1, l, mid, L, R, meta); if(mid < R) update(idx << 1 | 1, mid + 1, r, L, R, meta); tree[idx] = tree[idx << 1] == tree[idx << 1 | 1] ? tree[idx << 1] : -1; } int query(int idx, int l, int r){ if(tree[idx] != -1) return tree[idx] * (r - l + 1); int mid = (l + r) >> 1, ans = 0; ans += query(idx << 1, l, mid); ans += query(idx << 1 | 1, mid + 1, r); return ans; } int main(){ int T; scanf("%d", &T); for(int t = 1; t <= T; t++){ int n, m; scanf("%d%d", &n, &m); build(1, 1, n); for(int i = 0; i < m; i++){ int x, y, z; scanf("%d%d%d", &x, &y, &z); update(1, 1, n, x, y, z); } printf("Case %d: The total value of the hook is %d.\n", t, query(1, 1, n)); } return 0; }
思路:模板题。
#include<iostream> #include<cstdio> #include<cstring> #define lc(root) (root << 1) #define rc(root) (root << 1 | 1) using namespace std; const int maxn = 5e4 + 5; struct Tree{ int mn, mx; } tree[maxn << 2]; void pushup(int root){ tree[root].mn = min(tree[lc(root)].mn, tree[rc(root)].mn); tree[root].mx = max(tree[lc(root)].mx, tree[rc(root)].mx); } void build(int root, int l, int r){ if(l == r){ int val; scanf("%d", &val); tree[root].mn = tree[root].mx = val; return; } int mid = (l + r) >> 1; build(root << 1, l, mid); build(root << 1 | 1, mid + 1, r); pushup(root); } Tree query(int root, int l, int r, int L, int R){ if(L <= l && r <= R){ Tree ans = {tree[root].mn, tree[root].mx}; return ans; } int mid = (l + r) >> 1; Tree ans = {0x3f3f3f3f, 0}; if(L <= mid){ Tree res = query(root << 1, l, mid, L, R); ans.mn = min(ans.mn, res.mn); ans.mx = max(ans.mx, res.mx); } if(mid < R){ Tree res = query(root << 1 | 1, mid + 1, r, L, R); ans.mn = min(ans.mn, res.mn); ans.mx = max(ans.mx, res.mx); } return ans; } int main(){ int N, Q; scanf("%d%d", &N, &Q); build(1, 1, N); for(int i = 0; i < Q; i++){ int A, B; scanf("%d%d", &A, &B); Tree ans = query(1, 1, N, A, B); printf("%d\n", ans.mx - ans.mn); } return 0; }
HDU4027 Can you answer these queries?
思路:注意优化,算是比较坑的一题,但是学到了新的码风。
#include<iostream> #include<cstdio> #include<cstring> #include<cmath> #define LL long long #define mid ((l + r) >> 1) #define lc (root << 1) #define rc (root << 1 | 1) using namespace std; const int maxn = 1e5 + 5; LL tree[maxn << 2]; void build(int root, int l, int r){ if(l == r) return void(scanf("%lld", &tree[root])); build(lc, l, mid); build(rc, mid + 1, r); tree[root] = tree[lc] + tree[rc]; } void update(int root, int l, int r, int L, int R){ if(l > R || r < L || tree[root] == (r - l + 1)) return; if(l == r) return void(tree[root] = sqrt(tree[root])); update(lc, l, mid, L, R), update(rc, mid + 1, r, L, R); tree[root] = tree[lc] + tree[rc]; } LL query(int root, int l, int r, int L, int R){ if(l > R || r < L) return 0; if(L <= l && r <= R) return tree[root]; return query(lc, l, mid, L, R) + query(rc, mid + 1, r, L, R); } int main(){ int T = 0; int n, m; while(scanf("%d", &n) != EOF){ printf("Case #%d:\n", ++T); build(1, 1, n); scanf("%d", &m); for(int i = 0; i < m; i++){ int op, x, y; scanf("%d%d%d", &op, &x, &y); if(x > y) x ^= y ^= x ^= y; if(op == 0) update(1, 1, n, x, y); else printf("%lld\n", query(1, 1, n, x, y)); } printf("\n"); } return 0; }
思路:线段树有点复杂,网上的一个算法比较好,是用红黑树解决的,题目数据有点弱。
#include<iostream> #include<cstdio> #include<cstring> #include<set> #include<stack> #define LL long long using namespace std; int main(){ int n, m, x; char c; while(scanf("%d%d", &n, &m) != EOF){ stack<int> stk; set<int> st; st.insert(0), st.insert(n + 1); while(m--){ getchar(); scanf("%c", &c); if(c == 'R') st.erase(stk.top()), stk.pop(); else{ scanf("%d", &x); if(c == 'D') st.insert(x), stk.push(x); else if(st.find(x) != st.end()) printf("0\n"); else{ auto l = st.lower_bound(x), r = st.upper_bound(x); printf("%d\n", *r-*--l-1); } } } } return 0; }
思路:建树,每个employee指向直接boss。
#include<iostream> #include<cstdio> #include<cstring> #include<algorithm> #include<queue> #include<vector> using namespace std; const int maxn = 5e4 + 5; int n, m; int boss[maxn]; int tasks[maxn], sq[maxn]; void update(int e, int t, int id){ tasks[e] = t; sq[e] = id; } void query(int e){ int b = e, t = e; while(boss[b]){ if(sq[boss[b]] > sq[t]) t = boss[b]; b = boss[b]; } printf("%d\n", tasks[t]); } int main(){ int T; scanf("%d", &T); for(int t = 1; t <= T; t++){ scanf("%d", &n); memset(boss, 0, sizeof(boss)); for(int i = 0; i < n-1; i++){ int u, v; scanf("%d%d", &u, &v); boss[u] = v; } printf("Case #%d:\n", t); scanf("%d", &m); memset(tasks, -1, sizeof(tasks)); memset(sq, 0, sizeof(sq)); for(int i = 1; i <= m; i++){ char op[2]; int x, y; scanf("%s", op); if(op[0] == 'C'){ scanf("%d", &x); query(x); } else{ scanf("%d%d", &x, &y); update(x, y, i); } } } return 0; }
思路:题目比较烦,抄了其它人的暴力解法。
#include<iostream> #include<cstdio> #include<cstring> #include<cmath> using namespace std; const int maxn = 1e5 + 5; const int mod = 10007; int node[maxn << 2]; int n, m, op, p; void pushdown(int idx){ if(node[idx]==-1) return; node[idx<<1] = node[idx<<1|1] = node[idx]; node[idx] = -1; } void pushup(int idx){ if(node[idx<<1] == node[idx<<1|1]) node[idx] = node[idx<<1]; } void build(int idx, int l, int r){ node[idx] = 0; if(l == r) return; int mid = (l + r) >> 1; build(idx<<1, l, mid); build(idx<<1|1, mid+1, r); } void update(int idx, int l, int r, int L, int R){ if(L <= l && r <= R && node[idx] != -1){ if(op == 1) node[idx] = (node[idx] + p) % mod; else if(op == 2) node[idx] = (node[idx] * p) % mod; else node[idx] = p; return; } pushdown(idx); int mid = (l + r) >> 1; if(L <= mid) update(idx<<1, l, mid, L, R); if(mid < R) update(idx<<1|1, mid+1, r, L, R); pushup(idx); } int query(int idx, int l, int r, int L, int R){ if(L <= l && r <= R && node[idx] != -1){ return (long long)pow(node[idx], p) * (r - l + 1) % mod; } pushdown(idx); int mid = (l + r) >> 1, res = 0; if(L <= mid) res = (res + query(idx<<1, l, mid, L, R)) % mod; if(mid < R) res = (res + query(idx<<1|1, mid+1, r, L, R)) % mod; return res; } int main(){ while(~scanf("%d%d", &n, &m) && n){ build(1, 1, n); for(int i = 0; i < m; i++){ int x, y; scanf("%d%d%d%d", &op, &x, &y, &p); if(op < 4) update(1, 1, n, x, y); else printf("%d\n", query(1, 1, n, x, y)); } } return 0; }
思路:二分查找。
#include<iostream> #include<cstdio> #include<cstring> #include<vector> using namespace std; const int maxn = 5e4 + 5; int n, m; int val[maxn<<2], w[maxn<<2]; void pushdown(int idx, int n){ if(w[idx] != -1){ w[idx<<1] = w[idx<<1|1] = w[idx]; val[idx<<1] = (n - n/2) * w[idx]; val[idx<<1|1] = n/2 * w[idx]; w[idx] = -1; } } void build(int idx, int l, int r){ if(l == r){ val[idx] = 1, w[idx] = -1; return; } int mid = (l + r) >> 1; build(idx<<1, l, mid); build(idx<<1|1, mid+1, r); val[idx] = r - l + 1, w[idx] = -1; } void update(int idx, int l, int r, int L, int R, int v){ if(L<=l && r<=R){ w[idx] = v; val[idx] = (r - l + 1) * v; return; } pushdown(idx, r-l+1); int mid = (l + r) >> 1; if(L<=mid) update(idx<<1, l, mid, L, R, v); if(mid<R) update(idx<<1|1, mid+1, r, L, R, v); val[idx] = val[idx<<1] + val[idx<<1|1]; } int query(int idx, int l, int r, int L, int R){ if(L<=l && r<=R) return val[idx]; pushdown(idx, r-l+1); int mid = (l + r) >> 1, res = 0; if(L<=mid) res += query(idx<<1, l, mid, L, R); if(mid<R) res += query(idx<<1|1, mid+1, r, L, R); return res; } int search(int st, int num){ int l = st, r = n; int remain = query(1, 1, n, st, n); if(remain == 0) return -1; else if(remain < num){ return search(st, remain); } while(l < r){ int mid = (l + r) >> 1; int res = query(1, 1, n, st, mid); if(res >= num) r = mid; else if(res < num) l = mid+1; } return l; } void solve(int st, int num){ int l = search(st, 1), r = search(st, num); if(r == -1) { printf("Can not put any one.\n"); return; } printf("%d %d\n", l-1, r-1); update(1, 1, n, l, r, 0); } void print(int n){ for(int i = 1; i <= n; i++) cout << query(1, 1, n, i, i) << ' '; cout << endl; } int main(){ int T; scanf("%d", &T); while(T--){ scanf("%d%d", &n, &m); build(1, 1, n); for(int i = 0; i < m; i++){ int K, A, B; scanf("%d%d%d", &K, &A, &B); if(K == 1){ solve(A+1, B); } else { printf("%d\n", (B-A+1) - query(1, 1, n, A+1, B+1)); update(1, 1, n, A+1, B+1, 1); } } printf("\n"); } return 0; }