距离上一次写线段树有一年了,比赛一遇到卡了。后来发现当时非常不理解的懒惰标记(push_down)轻而易举的明白了,但是细节处理没写好。
带有懒惰标记的线段树一定要注意:
1. 访问到标记区间push_down后一定要清除标记。
2. 无论是update操作还是query操作一定要记得push_down,只要访问就要push_down
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <cmath>
#include <vector>
#include <stack>
#define INF (int)(1e9)
#define maxn 100100
#define Lson l, mid, rt << 1
#define Rson mid + 1, r, rt << 1 | 1
using namespace std;
typedef long long ll;
ll sum[maxn << 2];
ll now[maxn << 2];
ll fab[maxn << 2];
bool mark[maxn << 2];
ll fun(ll n) {
if (n <= 0ll) return 1ll;
for (int i = 0; i < 87; ++ i) {
if (fab[i] <= n && fab[i+1] >= n) {
if (abs(n-fab[i]) < abs(n-fab[i+1])) return fab[i];
else if (abs(n-fab[i]) > abs(n-fab[i+1])) return fab[i+1];
return fab[i];
}
}
return -1;
}
void push_down(int rt) {
if (mark[rt]) {
mark[rt << 1] = 1;
mark[rt << 1 | 1] = 1;
sum[rt << 1] = now[rt << 1];
sum[rt << 1 | 1] = now[rt << 1 | 1];
mark[rt] = 0;
}
}
void push_up(int rt) {
sum[rt] = sum[rt << 1] + sum[rt << 1 | 1];
}
void push_up1(int rt) {
now[rt] = now[rt << 1] + now[rt << 1 | 1];
}
void build(int l, int r, int rt) {
if (l == r) {
sum[rt] = 0;
now[rt] = 1;
return;
}
int mid = (l + r) >> 1;
build(Lson);
build(Rson);
push_up(rt);
push_up1(rt);
}
void update(int p, ll add, int l, int r, int rt) {
if (l == r) {
sum[rt] += add;
now[rt] = fun(sum[rt]);
return;
}
push_down(rt);
int mid = (l + r) >> 1;
if (p <= mid) {
update(p, add, Lson);
} else {
update(p, add, Rson);
}
push_up(rt);
push_up1(rt);
}
void update1(int L, int R, int l, int r, int rt) {
if (L <= l && r <= R) {
mark[rt] = 1;
sum[rt] = now[rt];
return;
}
push_down(rt);
int mid = (l + r) >> 1;
if (L <= mid)
update1(L, R, Lson);
if (R > mid)
update1(L, R, Rson);
push_up(rt);
}
ll query(int L, int R, int l, int r, int rt) {
if (L <= l && r <= R) {
return sum[rt];
}
push_down(rt);
ll ret = 0;
int mid = (l + r) >> 1;
if (L <= mid) {
ret += query(L, R, Lson);
}
if (R > mid) {
ret += query(L, R, Rson);
}
return ret;
}
int main() {
int n, m, c;
fab[0] = 1, fab[1] = 1;
for (int i = 2; i < 92; ++ i) fab[i] = fab[i-1] + fab[i-2];
while (scanf("%d%d", &n, &m) != EOF) {
memset(mark, 0, sizeof(mark));
build(1,n,1);
while (m --) {
scanf("%d", &c);
if (c == 1) {
int k, d;
scanf("%d%d", &k, &d);
update(k,d,1,n,1);
} else if (c == 2) {
int l, r;
scanf("%d%d", &l, &r);
printf("%lld\n", query(l,r,1,n,1));
} else if (c == 3) {
int l, r;
scanf("%d%d", &l, &r);
update1(l,r,1,n,1);
}
}
}
}