线段树 lazy tag 小合集
来源:互联网 发布:彩虹六号枪械数据 编辑:程序博客网 时间:2024/06/09 19:35
(这里的基础和进阶纯粹是根据PO主水平说的…大家意思意思看看就好Orz)
- 基础
- poj 3468
- hiho 1078
- poj 2777
- hdu 4902
- 进阶
- hdu 3911
- hdu 3397
- 未完待续
基础
poj 3468
题目链接
题意:
两种操作:
1. 对一段区间中的每一个数都加上一个值
2. 询问区间和
我学习 lazy tag 的第一道题,可以说是十分经典的模板题了,看了dalao的博客然后模仿着写了一遍
这道题比较重要的地方是 tag 的叠加性,在之后的另一道题(hdu 3911)里面会发现很容易忽略掉
AC代码如下:
#include <cstdio>#define MAX 100010typedef long long LL;struct node { int l, r, len; LL tag, sum;}tree[MAX * 4];void push_down(int rt) { if (tree[rt].tag) { LL tag = tree[rt].tag; tree[rt * 2].tag += tag; tree[rt * 2 + 1].tag += tag; tree[rt * 2].sum += tag * tree[rt * 2].len; tree[rt * 2 + 1].sum += tag * tree[rt * 2 + 1].len; tree[rt].tag = 0; }}void lift_up(int rt) { tree[rt].sum = tree[rt * 2].sum + tree[rt * 2 + 1].sum;}void build(int rt, int l, int r) { tree[rt].l = l; tree[rt].r = r; tree[rt].len = r - l + 1; if (l == r) { scanf("%lld", &tree[rt].sum); return; } int mid = (l + r) / 2; build(rt * 2, l, mid); build(rt * 2 + 1, mid + 1, r); lift_up(rt);}void update(int rt, int l, int r, LL val) { if (l == tree[rt].l && r == tree[rt].r) { tree[rt].sum += (LL)tree[rt].len * val; tree[rt].tag += val; return; } push_down(rt); int mid = (tree[rt].l + tree[rt].r) / 2; if (r <= mid) update(rt * 2, l, r, val); else if (l > mid) update(rt * 2 + 1, l, r, val); else { update(rt * 2, l, mid, val); update(rt * 2 + 1, mid + 1, r, val); } lift_up(rt);}LL query(int rt, int l, int r) { if (l == tree[rt].l && r == tree[rt].r) { return tree[rt].sum; } push_down(rt); int mid = (tree[rt].l + tree[rt].r) / 2; if (r <= mid) return query(rt * 2, l, r); else if (l > mid) return query(rt * 2 + 1, l, r); else return query(rt * 2, l, mid) + query(rt * 2 + 1, mid + 1, r);}int main() {// freopen("3468.in", "r", stdin);// freopen("3468.out", "w", stdout); int n, q; scanf("%d%d\n", &n ,&q); build(1, 1, n); scanf("\n"); for (int i = 0; i < q; ++i) { char ch; int l, r; scanf("%c", &ch); if (ch == 'Q') { scanf("%d%d\n", &l, &r); printf("%lld\n", query(1, l, r)); } else { int val; scanf("%d%d%d\n", &l, &r, &val); update(1, l, r, val); } } return 0;}
hiho 1078
题目链接
题意:
两种操作:
1. 将一段区间内的值修改为给定的值
2. 询问区间和
与第一道题基本相同,但比第一题更水些,tag都不需要叠加
AC代码如下:
#include <cstdio>#define maxn 100010#define lson ((rt) << 1)#define rson ((rt) << 1 | 1)inline int midi(int l, int r) { return (l + r) >> 1; }struct node { int l, r, val, len, tag;}tree[maxn * 4];void lift_up(int rt) { tree[rt].val = tree[lson].val + tree[rson].val;}void push_down(int rt) { if (tree[rt].tag) { tree[lson].val = tree[rt].tag * tree[lson].len; tree[rson].val = tree[rt].tag * tree[rson].len; tree[lson].tag = tree[rson].tag = tree[rt].tag; tree[rt].tag = 0; }}void build(int rt, int l, int r) { tree[rt].l = l; tree[rt].r = r; tree[rt].len = r - l + 1; if (l == r) { scanf("%d", &tree[rt].val); return; } int mid = midi(l, r); build(lson, l, mid); build(rson, mid + 1, r); lift_up(rt);}void modify(int rt, int l, int r, int val) {// printf("%d %d %d\n", rt, l, r); if (tree[rt].l == l && tree[rt].r == r) { tree[rt].val = tree[rt].len * val;// printf("val : %d\n", tree[rt].len); tree[rt].tag = val; return; } push_down(rt); int mid = midi(tree[rt].l, tree[rt].r);// printf("mid %d\n", mid); if (r <= mid) modify(lson, l, r, val); else if (l > mid) modify(rson, l, r, val); else { modify(lson, l, mid, val); modify(rson, mid + 1, r, val); } lift_up(rt);}int query(int rt, int l, int r) { if (tree[rt].l == l && tree[rt].r == r) return tree[rt].val; push_down(rt); int mid = midi(tree[rt].l, tree[rt].r); if (r <= mid) return query(lson, l, r); else if (l > mid) return query(rson, l, r); else return query(lson, l, mid) + query(rson, mid + 1, r);}int main() {// freopen("1078.in", "r", stdin); int n, m; scanf("%d", &n); build(1, 1, n); scanf("%d", &m); for (int i = 0; i < m; ++i) { int x, l, r; scanf("%d", &x); if (x == 0) { scanf("%d%d", &l, &r); printf("%d\n", query(1, l, r)); } else { int val; scanf("%d%d%d", &l, &r, &val); modify(1, l, r, val); } } return 0;}
poj 2777
题目链接
题意:
两种操作:
1. 将一段区间内的线段都涂成给定的颜色
2. 询问一段区间内共有多少种颜色
这道题有意思的地方在于,不需要额外用一个 tag 来做标记,而可以直接用这段区间本身的属性 color 来记录:
color == -1 表示这一段的颜色不统一;
color != -1 表示这一段的颜色统一,这就充当了 tag 的作用,向下更新或者向下查询,到此即可停止;若区间更小,则需要将这个信息 push 下去
AC代码如下:
#include <cstdio>#include <cstring>#define lson ((rt) << 1)#define rson ((rt) << 1 | 1)#define maxn 100010int ans[50];inline int midi(int l, int r) { return (l + r) >> 1; }struct node { int l, r, color;}tree[maxn * 4];void build(int rt, int l, int r) { tree[rt].l = l; tree[rt].r = r; if (rt != 1) tree[rt].color = 0; if (l == r) return; int mid = midi(l, r); build(lson, l, mid); build(rson, mid + 1, r);}void lift_up(int rt) { if (tree[lson].color == tree[rson].color) tree[rt].color = tree[lson].color;}void push_down(int rt) { if (tree[rt].color) { tree[lson].color = tree[rson].color = tree[rt].color; tree[rt].color = 0; }}void modify(int rt, int l, int r, int c) { if (tree[rt].l == l && tree[rt].r == r) { tree[rt].color = c; return; } push_down(rt); int mid = midi(tree[rt].l, tree[rt].r); if (r <= mid) modify(lson, l, r, c); else if (l > mid) modify(rson, l, r, c); else { modify(lson, l, mid, c); modify(rson, mid + 1, r, c); } lift_up(rt);}void query(int rt, int l, int r) {// printf("%d %d\n", rt, tree[rt].color); if (tree[rt].color) { ans[tree[rt].color] = true; return; } int mid = midi(tree[rt].l, tree[rt].r); if (r <= mid) query(lson, l, r); else if (l > mid) query(rson, l, r); else { query(lson, l, mid); query(rson, mid + 1, r); }}int main() { int n, t, o; scanf("%d%d%d", &n, &t, &o); tree[1].color = 1; build(1, 1, n); for (int i = 0; i < o; ++i) { char ch; scanf("\n%c", &ch); int l, r; if (ch == 'C') { int c; scanf("%d%d%d", &l, &r, &c); modify(1, l, r, c); } else { memset(ans, 0, sizeof(ans)); scanf("%d%d", &l, &r); query(1, l, r); int tot = 0; for (int k = 1; k <= t; ++k) if (ans[k]) ++tot; printf("%d\n", tot); } } return 0;}
hdu 4902
题目链接
题意:
两种操作:
1. 将一段区间内的数变为给定的值 x
2. 将一段区间内大于 x 的 ai 变为 gcd(x, ai)
最后输出序列
一开始想通过 tag 的叠加性来记录操作1和操作2产生的效果,
因为操作1能够抵消之前所有操作的影响,操作2(…我也不知道我当时怎么想的)
后来就乖乖地常规地写了,类似于之前涂色的那道题,每一段有个 val 属性
val != -1 表示这一段的值不统一,
val == -1 表示这一段有统一的值,可以统一进行 gcd 操作
AC代码如下:
#include <cstdio>#define lson ((rt) << 1)#define rson ((rt) << 1 | 1)#define maxn 100010inline midi(int l, int r) { return (l + r) >> 1; }int n;struct node { int l, r, val, tag;}tree[maxn * 4];int gcd(int a, int b) { if (b == 0) return a; return gcd(b, a % b);}void lift_up(int rt) { if (tree[lson].val == tree[rson].val) tree[rt].val = tree[lson].val;}void build(int rt, int l, int r) { tree[rt].l = l; tree[rt].r = r; tree[rt].val = -1; if (l == r) { scanf("%d", &tree[rt].val); return; } int mid = midi(l, r); build(lson, l, mid); build(rson, mid + 1, r); lift_up(rt);}void push_down(int rt) { if (tree[rt].val != -1) { tree[lson].val = tree[rson].val = tree[rt].val; tree[rt].val = -1; }}void modify1(int rt, int l, int r, int x) { if (tree[rt].l == l && tree[rt].r == r) { tree[rt].val = x; return; } push_down(rt); int mid = midi(tree[rt].l, tree[rt].r); if (r <= mid) modify1(lson, l, r, x); else if (l > mid) modify1(rson, l, r, x); else { modify1(lson, l, mid, x); modify1(rson, mid + 1, r, x); } lift_up(rt);}void modify2(int rt, int l, int r, int x) {// printf("%d %d %d\n", rt, l, r); if (tree[rt].l == l && tree[rt].r == r && tree[rt].val > -1) { if (tree[rt].val > x) tree[rt].val = gcd(tree[rt].val, x); return; } push_down(rt); int mid = midi(tree[rt].l, tree[rt].r); if (r <= mid) modify2(lson, l, r, x); else if (l > mid) modify2(rson, l, r, x); else { modify2(lson, l, mid, x); modify2(rson, mid + 1, r, x); } lift_up(rt);}void print(int rt, int l, int r) {// printf("%d %d %d\n", rt, l, r); if (tree[rt].val > -1) { for (int i = l; i <= r; ++i) printf("%d ", tree[rt].val); return; } int mid = midi(tree[rt].l, tree[rt].r); print(lson, l, mid); print(rson, mid + 1, r);}void work() { build(1, 1, n); int m; scanf("%d", &m); for (int i = 0; i < m; ++i) { int t, l, r, x; scanf("%d%d%d%d", &t, &l, &r, &x); if (t == 1) modify1(1, l, r, x); else modify2(1, l, r, x); } print(1, 1, n); printf("\n");}int main() {// freopen("4902.in", "r", stdin);// freopen("4902.out", "w", stdout); int T; scanf("%d", &T); while (scanf("%d", &n) != EOF) work(); return 0;}
进阶
hdu 3911
hdu 3397
具体见 http://blog.csdn.net/kkkkahlua/article/details/75125877
未完待续
- 线段树 lazy tag 小合集
- 线段树Lazy-tag
- 线段树及Lazy-Tag
- 线段树多lazy-tag(两个)
- POJ3468 线段树 + Lazy Tag (延迟标记)
- hdu 3911, 3397 线段树 lazy tag
- POJ 3667 Hotel 【线段树 区间合并 + Lazy-tag】
- AHOI2009维护序列--线段树lazy tag模板
- 线段树——区间修改(Lazy-Tag)
- [CodeVS 4927] 线段树练习5:两个Lazy Tag的线段树
- poj 2777 Count Color(线段树 Lazy-Tag思想 成段更新+区间统计)
- poj 1823 Hotel(线段树·区间更新·lazy tag)
- poj 3225 Help with Intervals 线段树lazy-tag求解区间运算
- [bzoj 3064] Tyvj 1518 CPU监控:线段树的Lazy tag
- HDU 1698Just a Hook(线段树 + Lazy Tag(延迟更新))
- POJ 3468A Simple Problem with Integers(线段树 + Lazy Tag(延迟更新))
- POJ 3667 Hotel(线段树的合并+lazy tag)【很详细!!】
- POJ 2777 Count Color (线段树的区间更新+lazy tag)
- 逻辑回归LR
- 每日一题——寻找倒数第k个节点
- 给UICollectionView 添加sectionhead 和sectionfoot
- Inside ELF Symbol Tables
- 量化投资与数据分析一: 如何用PYTHON下载WIND数据并转化成dataframe格式 分享
- 线段树 lazy tag 小合集
- 平方Pearson相关系数(SPCC)相关公式的推导
- LinearLayout通过shape设置圆角,但是最下面的textView却没有圆角
- Java保留两位小数
- 微信支付二维码
- h2o-python
- 1. Two Sum
- 2017年7月7日,周结(二十一),Activity的构成、Snackbar和TextInputLayout 的使用
- 发布高质量外链的实用方法