[kuangbin带你飞]专题七 线段树 【A、B、C、E、G、H】
2017-04-18 12:48
405 查看
题目链接:点击打开链接
A - 敌兵布阵
HDU - 1166单点更新及区间求和。
更新时是在原有的基础上进行加减,直接进行加减即可。
AC代码:
#include <cstdio> #include <iostream> #include <cstring> #include <algorithm> #include <cmath> using namespace std; const int INF = 0x3f3f3f3f; const int MAX = 50010; long long ans; struct node { int l, r; int sum; } tree[MAX<<2]; void pushup(int rt) { tree[rt].sum = tree[rt<<1].sum + tree[rt<<1|1].sum; } void build(int l, int r, int rt) { tree[rt].l = l; tree[rt].r = r; tree[rt].sum = 0; if(l == r) //叶子结点 { scanf("%d",&tree[rt].sum); return ; } int mid = (l+r)>>1; //递归建树 build(l, mid, rt<<1); build(mid+1, r, rt<<1|1); pushup(rt); } void update(int pos, int val, int rt) { //更新这个区间的值 if(tree[rt].l == tree[rt].r) { tree[rt].sum += val; return ; } int mid = (tree[rt].l+tree[rt].r)>>1; if(pos <= mid) update(pos, val, rt<<1); else update(pos, val, rt<<1|1); pushup(rt); } void query(int x, int y, int rt) { if(x == tree[rt].l && y == tree[rt].r) { ans += tree[rt].sum; return ; } int mid = (tree[rt].l+tree[rt].r)>>1; if(y <= mid) query(x, y, rt<<1); else if(x > mid) query(x, y, rt<<1|1); else { query(x, mid, rt<<1); query(mid+1, y, rt<<1|1); } } int main() { int T; int n, pos, val; string s; scanf("%d",&T); for(int cas = 1; cas <= T; ++cas) { printf("Case %d:\n",cas); scanf("%d",&n); build(1, n, 1); while(cin >> s) { if(s == "End") break; scanf("%d%d",&pos,&val); if(s == "Add") { update(pos, val, 1); } else if(s == "Sub") { update(pos, -val, 1); } else if(s == "Query") { ans = 0; int x = pos; int y = val; if(x > y) swap(x, y); query(x, y, 1); cout << ans << endl; } } } return 0; }
B - I Hate It
HDU - 1754单点更新及区间最大值。
与A题不同的是,这里的单点更新是直接对数值进行替换,所以直接赋值即可。
AC代码:
#include <cstdio> #include <iostream> #include <cstring> #include <algorithm> #include <cmath> using namespace std; const int INF = 0x3f3f3f3f; const int MAX = 200010; int ans; struct node { int l, r; int Max; } tree[MAX<<2]; void pushup(int rt) { tree[rt].Max = max(tree[rt<<1].Max, tree[rt<<1|1].Max); } void build(int l, int r, int rt) { tree[rt].l = l; tree[rt].r = r; if(l == r) //叶子结点 { scanf("%d",&tree[rt].Max); return ; } int mid = (l+r)>>1; //递归建树 e43f build(l, mid, rt<<1); build(mid+1, r, rt<<1|1); pushup(rt); } void update(int pos, int val, int rt) { //更新这个区间的值 if(tree[rt].l == tree[rt].r) { tree[rt].Max = val; return ; } int mid = (tree[rt].l+tree[rt].r)>>1; if(pos <= mid) update(pos, val, rt<<1); else update(pos, val, rt<<1|1); pushup(rt); } void query(int x, int y, int rt) { if(tree[rt].l == x && tree[rt].r == y) { ans = max(ans, tree[rt].Max); return ; } int mid = (tree[rt].l+tree[rt].r)>>1; if(y <= mid) query(x, y, rt<<1); else if(x > mid) query(x, y, rt<<1|1); else { query(x, mid, rt<<1); query(mid+1, y, rt<<1|1); } } int main() { int n, m; int x, y; string q; while(~scanf("%d%d",&n,&m)) { build(1, n, 1); while(m--) { cin >> q >> x >> y; if(q == "Q") { ans = 0; query(x, y, 1); cout << ans << endl; } else update(x, y, 1); } } return 0; }
C - A Simple Problem with Integers
POJ - 3468区间更新及区间求和。
因为区间更新后的值不一定会一下子用到,所以进行延迟操作,通过lazy标记实现。
AC代码:
#include <cstdio> #include <iostream> #include <cstring> #include <algorithm> #include <cmath> using namespace std; const int INF = 0x3f3f3f3f; const int MAX = 100010; struct node { int l, r; long long sum, lazy; } tree[MAX<<2]; void pushup(int rt) { tree[rt].sum = tree[rt<<1].sum + tree[rt<<1|1].sum; } void pushdown(int rt) //延迟操作,更新当前结点的叶子 { int len = tree[rt].r - tree[rt].l + 1; tree[rt<<1].sum += tree[rt].lazy*(len-len/2); tree[rt<<1|1].sum += tree[rt].lazy*(len/2); tree[rt<<1].lazy += tree[rt].lazy; tree[rt<<1|1].lazy += tree[rt].lazy; tree[rt].lazy = 0; } void build(int l, int r, int rt) { tree[rt].l = l; tree[rt].r = r; tree[rt].sum = tree[rt].lazy = 0; if(l == r) { scanf("%lld",&tree[rt].sum); return ; } int mid = (l+r)>>1; //递归建树 build(l, mid, rt<<1); build(mid+1, r, rt<<1|1); pushup(rt); } void update(int x, int y, long long val, int rt) { //更新这个区间的值 if(tree[rt].l == x && tree[rt].r == y) { tree[rt].lazy += val; tree[rt].sum += (y-x+1)*val; return ; } if(tree[rt].lazy) pushdown(rt); //向下更新枝叶的值 int mid = (tree[rt].l+tree[rt].r)>>1; if(y <= mid) update(x, y, val, rt<<1); else if(x > mid) update(x, y, val, rt<<1|1); else { update(x, mid, val, rt<<1); update(mid+1, y, val, rt<<1|1); } pushup(rt); } long long query(int x, int y, int rt) { if(tree[rt].l == x && tree[rt].r == y) return tree[rt].sum; if(tree[rt].lazy) pushdown(rt); //向下更新枝叶的值 int mid = (tree[rt].l+tree[rt].r)>>1; if(y <= mid) return query(x, y, rt<<1); else if(x > mid) return query(x, y, rt<<1|1); else return query(x, mid, rt<<1) + query(mid+1, y, rt<<1|1); } int main() { int n, m; int x, y; string q; while(~scanf("%d%d",&n,&m)) { build(1, n, 1); while(m--) { cin >> q; scanf("%d%d",&x,&y); if(q == "Q") { cout << query(x, y, 1) << endl; } else { long long val; scanf("%lld",&val); update(x, y, val, 1); } } } return 0; }
D - Mayor's posters
POJ - 2528E - Just a Hook
HDU - 1698区间更新(值替换)及区间求和,和C一样的做法,只不过在处理lazy及sum时 += 换为了 =。
AC代码:
#include <cstdio> #include <iostream> #include <cstring> #include <algorithm> #include <cmath> using namespace std; const int INF = 0x3f3f3f3f; const int MAX = 100010; int ans; struct node { int l, r; int sum, lazy; } tree[MAX<<2]; void pushup(int rt) { tree[rt].sum = tree[rt<<1].sum + tree[rt<<1|1].sum; } void pushdown(int rt) //延迟操作,更新当前结点的叶子 { int len = tree[rt].r - tree[rt].l + 1; tree[rt<<1].sum = tree[rt].lazy*(len-len/2); tree[rt<<1|1].sum = tree[rt].lazy*(len/2); tree[rt<<1].lazy = tree[rt].lazy; tree[rt<<1|1].lazy = tree[rt].lazy; tree[rt].lazy = 0; } void build(int l, int r, int rt) { tree[rt].l = l; tree[rt].r = r; tree[rt].sum = tree[rt].lazy = 0; if(l == r) { tree[rt].sum = 1; return ; } int mid = (l+r)>>1; //递归建树 build(l, mid, rt<<1); build(mid+1, r, rt<<1|1); pushup(rt); } void update(int x, int y, int val, int rt) { //更新这个区间的值 if(tree[rt].l == x && tree[rt].r == y) { tree[rt].lazy = val; tree[rt].sum = (y-x+1)*val; return ; } if(tree[rt].lazy) pushdown(rt); //向下更新枝叶的值 int mid = (tree[rt].l+tree[rt].r)>>1; if(y <= mid) update(x, y, val, rt<<1); else if(x > mid) update(x, y, val, rt<<1|1); else { update(x, mid, val, rt<<1); update(mid+1, y, val, rt<<1|1); } pushup(rt); } int query(int x, int y, int rt) { if(tree[rt].l == x && tree[rt].r == y) return tree[rt].sum; if(tree[rt].lazy) pushdown(rt); //向下更新枝叶的值 int mid = (tree[rt].l+tree[rt].r)>>1; if(y <= mid) return query(x, y, rt<<1); else if(x > mid) return query(x, y, rt<<1|1); else return query(x, mid, rt<<1) + query(mid+1, y, rt<<1|1); } int main() { int T; int n, m; int x, y, z; scanf("%d",&T); for(int i = 1; i <= T; ++i) { ans = 0; scanf("%d%d",&n,&m); build(1, n, 1); while(m--) { scanf("%d%d%d",&x,&y,&z); update(x, y, z, 1); } ans = query(1, n, 1); printf("Case %d: The total value of the hook is %d.\n",i,ans); } return 0; }
F - Count the Colors
ZOJ - 1610G - Balanced Lineup
POJ - 3264查询区间最大值与最小值之差。
AC代码:
#include <cstdio> #include <iostream> #include <cstring> #include <algorithm> #include <cmath> using namespace std; const int INF = 0x3f3f3f3f; const int MAX = 200010; int ans1, ans2; struct node { int l, r; int Max, Min; } tree[MAX<<2]; void pushup(int rt) { tree[rt].Max = max(tree[rt<<1].Max, tree[rt<<1|1].Max); tree[rt].Min = min(tree[rt<<1].Min, tree[rt<<1|1].Min); } void build(int l, int r, int rt) { tree[rt].l = l; tree[rt].r = r; if(l == r) //叶子结点 { scanf("%d",&tree[rt].Max); tree[rt].Min = tree[rt].Max; return ; } int mid = (l+r)>>1; //递归建树 build(l, mid, rt<<1); build(mid+1, r, rt<<1|1); pushup(rt); } void update(int pos, int val, int rt) { //更新这个区间的值 if(tree[rt].l == tree[rt].r) { tree[rt].Max = tree[rt].Min = val; return ; } int mid = (tree[rt].l+tree[rt].r)>>1; if(pos <= mid) update(pos, val, rt<<1); else update(pos, val, rt<<1|1); pushup(rt); } void qMax(int x, int y, int rt) { if(tree[rt].l == x && tree[rt].r == y) { ans1 = max(ans1, tree[rt].Max); return ; } int mid = (tree[rt].l+tree[rt].r)>>1; if(y <= mid) qMax(x, y, rt<<1); else if(x > mid) qMax(x, y, rt<<1|1); else { qMax(x, mid, rt<<1); qMax(mid+1, y, rt<<1|1); } } void qMin(int x, int y, int rt) { if(tree[rt].l == x && tree[rt].r == y) { ans2 = min(ans2, tree[rt].Min); return ; } int mid = (tree[rt].l+tree[rt].r)>>1; if(y <= mid) qMin(x, y, rt<<1); else if(x > mid) qMin(x, y, rt<<1|1); else { qMin(x, mid, rt<<1); qMin(mid+1, y, rt<<1|1); } } int main() { int n, m; int x, y; while(~scanf("%d%d",&n,&m)) { build(1, n, 1); while(m--) { ans1 = 0; ans2 = INF; scanf("%d%d",&x,&y); qMax(x, y, 1); qMin(x, y, 1); printf("%d\n",ans1-ans2); } } return 0; }
H - Can you answer these queries?
HDU - 4027区间更新及求和。
由于对数据开方后区间和没法与更新前的区间和建立递推关系,所以无法和C题一样处理数据。
不过最大的数(2^63)开7次方后也会变成1,所以我们每次直接更新到叶子结点,然后把叶子结点都已无法更新的根节点及叶子结点都标记一下,下次更新时略过就好了。
AC代码:
#include <cstdio> #include <iostream> #include <cstring> #include <algorithm> #include <cmath> using namespace std; const int INF = 0x3f3f3f3f; const int MAX = 100010; struct node { int l, r; long long sum; bool flag; } tree[MAX<<2]; void pushup(int rt) { tree[rt].sum = tree[rt<<1].sum + tree[rt<<1|1].sum; tree[rt].flag = tree[rt<<1].flag & tree[rt<<1|1].flag; //叶子结点是否已都更新到无法更新 } void build(int l, int r, int rt) { tree[rt].l = l; tree[rt].r = r; tree[rt].sum = tree[rt].flag = 0; if(l == r) { scanf("%lld",&tree[rt].sum); if(tree[rt].sum <= 1) tree[rt].flag = 1; return ; } int mid = (l+r)>>1; //递归建树 build(l, mid, rt<<1); build(mid+1, r, rt<<1|1); pushup(rt); } void update(int x, int y, int rt) { if(tree[rt].flag) return ; //这是一步是关键,省下了很多无用的操作 //更新这个区间的值 if(tree[rt].l == tree[rt].r) { tree[rt].sum = (long long)sqrt(tree[rt].sum*1.0); if(tree[rt].sum <= 1) tree[rt].flag = 1; return ; } int mid = (tree[rt].l+tree[rt].r)>>1; if(y <= mid) update(x, y, rt<<1); else if(x > mid) update(x, y, rt<<1|1); else { update(x, mid, rt<<1); update(mid+1, y, rt<<1|1); } pushup(rt); } long long query(int x, int y, int rt) { if(tree[rt].l == x && tree[rt].r == y) { return tree[rt].sum; } int mid = (tree[rt].l+tree[rt].r)>>1; if(y <= mid) return query(x, y, rt<<1); else if(x > mid) return query(x, y, rt<<1|1); else return query(x, mid, rt<<1) + query(mid+1, y, rt<<1|1); } int main() { int n, m; int q, x, y; int cou = 0; while(~scanf("%d",&n)) { printf("Case #%d:\n",++cou); build(1, n, 1); scanf("%d",&m); while(m--) { scanf("%d%d%d",&q,&x,&y); if(x > y) swap(x, y); if(q == 1) { cout << query(x, y, 1) << endl; } else { update(x, y, 1); } } puts(""); } return 0; }
相关文章推荐
- [kuangbin带你飞]专题七 线段树 B - I Hate It(单点修改,区间最大值)
- [kuangbin带你飞]专题七 线段树 A - 敌兵布阵 (单点修改,区间求和)
- [kuangbin带你飞]专题七 线段树
- [kuangbin带你飞]专题七 线段树 I HDU 1540
- 【算法系列学习】线段树 单点覆盖,区间查询最大值 [kuangbin带你飞]专题七 线段树 B - I Hate It
- 【算法系列学习】线段树 区间修改,区间求和 [kuangbin带你飞]专题七 线段树 C - A Simple Problem with Integers
- [kuangbin带你飞]专题七 线段树 F - Count the Colors(颜色覆盖)
- [kuangbin带你飞]专题七 线段树 G POJ 3264
- [kuangbin带你飞]专题七 线段树 H HDU-4027
- [kuangbin带你飞]专题七 线段树 B HDU 1754
- [kuangbin带你飞]专题七 线段树 J HDU 3974
- [kuangbin带你飞]专题七 线段树 C POJ 3468
- [kuangbin带你飞]专题七 线段树 G POJ 3264
- [kuangbin带你飞]专题七 线段树 ABCDE 题解,持续更新
- [kuangbin带你飞]专题七 线段树 H HDU4027
- [kuangbin带你飞]专题七 线段树 A HDU 1166
- 【算法系列学习】线段树vs树状数组 单点修改,区间查询 [kuangbin带你飞]专题七 线段树 A - 敌兵布阵
- [kuangbin带你飞]专题七 线段树 题解(未完)
- [kuangbin带你飞]专题七 线段树 C - A Simple Problem with Integers
- [kuangbin带你飞]专题七 线段树 E - Just a Hook