(这里的基础和进阶纯粹是根据PO主水平说的…大家意思意思看看就好Orz)
基础
poj 3468
题意:
两种操作:
1. 对一段区间中的每一个数都加上一个值
2. 询问区间和
我学习 lazy tag 的第一道题,可以说是十分经典的模板题了,看了dalao的博客然后模仿着写了一遍
这道题比较重要的地方是 tag 的叠加性,在之后的另一道题(hdu 3911)里面会发现很容易忽略掉
AC代码如下:
#include <cstdio>
#define MAX 100010
typedef 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 100010
int 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 100010
inline 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.youkuaiyun.com/kkkkahlua/article/details/75125877