关于动态开点线段树的应用

关于动态开点线段树的应用

自己瞎取的名字,就是动态开点线段树。
大概思想当空间不够用的时候,随时可以删点和新建点,比较灵活。
下面是几个例子,有的是值域线段树,有的是普通坐标的线段树。

本来是树状数组水题,现在变成了奇怪的动态开点值域线段树模板题。
其实不用值域线段树也可以。
普通线段树就要离散化然后按照单调递增的顺序加 value,再 query。
多麻烦啊,所以一个值域线段树解决问题。

因为最大值 MAX 为 $10^9$,所以 inf 设为 $10^9$。
因为每一次查询的是当前点往右的点数,所以要特判 l>r 的情况。
因为 inf=1e9,所以查询 1e9+1 就会炸掉,所以要特判。
其实把 inf 变成 1e9+10 不是一样的吗

那么代码如下。

因为线段树平均链深度为 $\log$ 级别。
所以开 $N \log N$ 大小的线段树。
动态开点线段树的优势在这道题还真没体现出来(

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
#include <bits/stdc++.h>
#define ll long long
using namespace std;

const int N = 1e7 + 10;
const int inf = 1e9 + 10;

int n, cnt, root, tree[N];
int a[N], ls[N], rs[N];

void read(int &ret) {
ret = 0; char ch = getchar();
while (!isdigit(ch)) ch = getchar();
while (isdigit(ch)) {
ret = (ret<<1) + (ret<<3) + (ch^48);
ch = getchar();
} return ;
}

void upd(int &rt, int l, int r, int val, int f) {
if (!rt) rt = ++cnt;
if (l==r) { tree[rt] += f; return ; }
int mid = (l+r) >> 1;
if (val<=mid) upd(ls[rt], l, mid, val, f);
else upd(rs[rt], mid+1, r, val, f);
tree[rt] = tree[ls[rt]] + tree[rs[rt]];
return ;
}

int query(int rt, int l, int r, int L, int R) {
if (!rt) return 0;
if (L<=l && r<=R) return tree[rt];
int mid = (l+r) >> 1, ans = 0;
if (L<=mid) ans += query(ls[rt], l, mid, L, R);
if (R>mid) ans += query(rs[rt], mid+1, r, L, R);
return ans;
}

int main() {
read(n); ll ans = 0;
for (int i=1; i<=n; ++i) {
int x; read(x);
ans += (ll)query(root, 1, inf, x+1, inf);
upd(root, 1, inf, x, 1);
}
printf("%lld\n", ans);
return 0;
}

跑了 4s 多,还不如写普通线段树(bu

虽然是个紫题,但是是个水紫。

首先问题可以简化成树上染色问题,四个 option 变成下面这样。

  • 某个节点被重新染色
  • 节点权值被修改
  • 求路径上某种颜色权值和
  • 求路径上某种颜色最大权值

那么考虑对于每一个颜色开一棵动态开点线段树。
然后直接树链剖分乱搞。(轻重链剖分)
对于 option 3 和 4 随便乱搞都可以过。

但是对于 option 1,可以转化为在树中删点,再丢到另一棵树里。
option 2 直接修改当前权值即可。

所以想到 pushup 操作。
可以将节点的 MAX 和 SUM 直接变成 0。
接着删点(就这么做!)跑路。
然后在另一棵树里面新建节点,只需要丢进去即可。
然后修改颜色(即要修改节点所属树根)。
或者是修改当前的权值。注意要 remove 和 update 之后做。

然后就没了。

似乎并不毒瘤?

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
#include <bits/stdc++.h>
using namespace std;

void read(int &ret) {
ret = 0; char ch = getchar();
while (!isdigit(ch)) ch = getchar();
while (isdigit(ch)) {
ret = (ret<<1) + (ret<<3) + (ch^48);
ch = getchar();
} return ;
}

const int MAXN = 1e5 + 10;
const int MAX_SIZE = 2e7;

int n, Q, cnt, tot/*build-cnt*/, idx;
int w[MAXN], c[MAXN], wl[MAXN], wc[MAXN];
int dep[MAXN], siz[MAXN], fa[MAXN], son[MAXN];
int tp[MAXN], root[MAXN], id[MAXN];
char opt[3]; int head[MAXN<<1];

struct Edge { int to, nxt; } e[MAXN<<1];
void addEdge(int u, int v) {
e[++cnt].to = v;
e[cnt].nxt = head[u];
head[u] = cnt; return ;
}

void dfs1(int cur, int f) {
fa[cur] = f, siz[cur] = 1;
dep[cur] = dep[f] + 1;
int heavyson = -1;
for (int i=head[cur]; i; i=e[i].nxt) {
int to = e[i].to;
if (to == f) continue;
dfs1(to, cur), siz[cur] += siz[to];
if (siz[to] > heavyson)
heavyson = siz[to], son[cur] = to;
} return ;
}

void dfs2(int cur, int Tp) {
tp[cur] = Tp, id[cur] = ++idx;
if (!son[cur]) return ;
dfs2(son[cur], Tp);
for (int i=head[cur]; i; i=e[i].nxt) {
int to = e[i].to;
if (to==fa[cur] || to==son[cur]) continue;
dfs2(to, to);
} return ;
}

struct seg { int ls, rs, Max, val; } tree[MAX_SIZE];
void pushup(int rt) {
tree[rt].val = tree[tree[rt].ls].val + tree[tree[rt].rs].val;
tree[rt].Max = max(tree[tree[rt].ls].Max, tree[tree[rt].rs].Max);
return ;
}

void upd(int &rt, int l, int r, int pos, int W) {
if (!rt) rt = ++tot;
if (l==r) { tree[rt].val = tree[rt].Max = W; return ; }
int mid = (l+r) >> 1;
if (pos<=mid) upd(tree[rt].ls, l, mid, pos, W);
else upd(tree[rt].rs, mid+1, r, pos, W);
pushup(rt); return ;
}

void remv(int rt, int l, int r, int pos) {
if (l==r) { tree[rt].val = tree[rt].Max = 0; return ; }
int mid = (l+r) >> 1;
if (pos<=mid) remv(tree[rt].ls, l, mid, pos);
else remv(tree[rt].rs, mid+1, r, pos);
pushup(rt); return ;
}

int querys(int rt, int l, int r, int L, int R) {
if (L<=l && r<=R) return tree[rt].val;
int mid = (l+r) >> 1, ans = 0;
if (L<=mid) ans += querys(tree[rt].ls, l, mid, L, R);
if (R>mid) ans += querys(tree[rt].rs, mid+1, r, L, R);
return ans;
}

int querym(int rt, int l, int r, int L, int R) {
if (L<=l && r<=R) return tree[rt].Max;
int mid = (l+r) >> 1, ans = 0;
if (L<=mid) ans = max(ans, querym(tree[rt].ls, l, mid, L, R));
if (R>mid) ans = max(ans, querym(tree[rt].rs, mid+1, r, L, R));
return ans;
}

int qus(int l, int r, int rel) {
int ans = 0;
while (tp[l] ^ tp[r]) {
if (dep[tp[l]] < dep[tp[r]]) swap(l, r);
ans += querys(root[rel], 1, n, id[tp[l]], id[l]);
l = fa[tp[l]];
}
if (dep[l] > dep[r]) swap(l, r);
ans += querys(root[rel], 1, n, id[l], id[r]);
return ans;
}

int qum(int l, int r, int rel) {
int ans = 0;
while (tp[l] ^ tp[r]) {
if (dep[tp[l]] < dep[tp[r]]) swap(l, r);
ans = max(ans, querym(root[rel], 1, n, id[tp[l]], id[l]));
l = fa[tp[l]];
}
if (dep[l] > dep[r]) swap(l, r);
ans = max(ans, querym(root[rel], 1, n, id[l], id[r]));
return ans;
}

int main() {
read(n), read(Q);
for (int i=1; i<=n; ++i)
read(w[i]), read(c[i]);
for (int i=1; i<n; ++i) {
int u, v; read(u), read(v);
addEdge(u, v);
addEdge(v, u);
}
dfs1(1, 1), dfs2(1, 1);
for (int i=1; i<=n; ++i)
upd(root[c[i]], 1, n, id[i], w[i]);
while (Q--) {
cin >> opt+1;
int u, v; read(u), read(v);
if (opt[2] == 'C') {
remv(root[c[u]], 1, n, id[u]);
upd(root[v], 1, n, id[u], w[u]);
c[u] = v;
} else if (opt[2] == 'W') {
remv(root[c[u]], 1, n, id[u]);
upd(root[c[u]], 1, n, id[u], v);
w[u] = v;
} else if (opt[2] == 'S') printf("%d\n", qus(u, v, c[u]));
else if (opt[2] == 'M') printf("%d\n", qum(u, v, c[u]));
}
return 0;
}
Author

Xcel

Posted on

2021-08-04

Updated on

2021-09-04

Licensed under

Your browser is out-of-date!

Update your browser to view this website correctly.&npsb;Update my browser now

×