-平衡树-启发式合并-并查集- [洛谷 P4556][Vani有约会]雨天的尾巴

题目描述

Link

Solution

对于每个点开一个平衡树,平衡树的节点保存的信息有:粮食id,这个粮食的数量,平衡树内子树中最多的粮食的id,平衡树内子树中最多的粮食的数量。

我们需要把update函数变换一下,让他不仅更新子树大小还更新关于粮食的信息。

那么如何修改呢?我们可以运用树上差分进行修改,最后再进行平衡树启发式合并。

Code

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
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <ctime>
#define MAXN 101000
#define LOG 20
struct Treap {
int v, dat, num;
int cnt, siz, maxx, maxid;
int l, r;
}a[MAXN * LOG << 2];
struct Edge {
int v, nx;
}e[MAXN << 1];
int tot, rt[MAXN], head[MAXN], ecnt, anc[MAXN][LOG + 1], dep[MAXN], ans[MAXN], fa[MAXN];
void add(int f, int t) {
e[++ecnt] = (Edge) {t, head[f]};
head[f] = ecnt;
}
int New(int val, int num) {
tot++;
a[tot].v = val;
a[tot].num = num;
a[tot].dat = rand();
a[tot].cnt = a[tot].siz = 1;
a[tot].maxx = num;
a[tot].maxid = val;
return tot;
}
void update(int p) {
a[p].siz = a[p].cnt + a[a[p].l].siz + a[a[p].r].siz;
a[p].maxx = a[p].num;
a[p].maxid = a[p].v;
int maxx = a[p].maxx, maxid = a[p].maxid;
if (a[a[p].l].maxx > maxx || (a[a[p].l].maxx == maxx && a[a[p].l].maxid < maxid)) {
maxx = a[a[p].l].maxx;
maxid = a[a[p].l].maxid;
}
if (a[a[p].r].maxx > maxx || (a[a[p].r].maxx == maxx && a[a[p].r].maxid < maxid)) {
maxx = a[a[p].r].maxx;
maxid = a[a[p].r].maxid;
}
a[p].maxx = maxx;
a[p].maxid = maxid;
}
void zig(int &p) {
int q = a[p].l;
a[p].l = a[q].r, a[q].r = p, p = q;
update(a[p].r), update(p);
}
void zag(int &p) {
int q = a[p].r;
a[p].r = a[q].l, a[q].l = p, p = q;
update(a[p].l), update(p);
}
void insert(int &p, int val, int num) {
if (!p) {
p = New(val, num);
return;
}
if (val == a[p].v) {
a[p].num += num;
update(p);
return;
}
if (val < a[p].v) {
insert(a[p].l, val, num);
if (a[p].dat < a[a[p].l].dat) zig(p);
}
else {
insert(a[p].r, val, num);
if (a[p].dat < a[a[p].r].dat) zag(p);
}
update(p);
}
int find(int x) {
if (x == fa[x]) return x;
else return fa[x] = find(fa[x]);
}
void merge(int x, int y) {
if (!y) return;
insert(rt[x], a[y].v, a[y].num);
merge(x, a[y].l);
merge(x, a[y].r);
}
void dfs(int f, int u, int d) {
dep[u] = d;
for (int i = head[u]; i; i = e[i].nx) {
int to = e[i].v;
if (to == f) continue;
anc[to][0] = u;
dfs(u, to, d + 1);
}
}
void swim(int &x, int h) {
for (int i = 0; h; i++) {
if (h & 1) x = anc[x][i];
h >>= 1;
}
}
int LCA(int x, int y) {
if (dep[x] < dep[y]) std::swap(x, y);
swim(x, dep[x] - dep[y]);
if (x == y) return x;
for (int i = LOG; i >= 0; i--) {
if (anc[x][i] != anc[y][i]) {
x = anc[x][i];
y = anc[y][i];
}
}
return anc[x][0];
}
void dfs1(int f, int u) {
for (int i = head[u]; i; i = e[i].nx) {
int to = e[i].v;
if (to == f) continue;
dfs1(u, to);
int x = find(u);
int y = find(to);
if (a[rt[x]].siz < a[rt[y]].siz) std::swap(x, y);
fa[y] = x;
// printf("Merge: %d --> %d\n", y, x);
merge(x, rt[y]);
}
int q = find(u);
ans[u] = a[rt[q]].maxid;
}
int n, m, x, y, z;
int main() {
srand(time(NULL));
scanf("%d%d", &n, &m);
for (int i = 1; i < n; i++) {
scanf("%d%d", &x, &y);
add(x, y);
add(y, x);
}
for (int i = 1; i <= n; i++) {
fa[i] = i;
}
dfs(1, 1, 1);
for (int i = 1; i <= LOG; i++) {
for (int j = 1; j <= n; j++) {
anc[j][i] = anc[anc[j][i - 1]][i - 1];
}
}
while (m--) {
scanf("%d%d%d", &x, &y, &z);
insert(rt[x], z, 1);
insert(rt[y], z, 1);
int lc = LCA(x, y);
// printf("%d\n", lc);
insert(rt[lc], z, -1);
// if (lc == 1) continue;
insert(rt[anc[lc][0]], z, -1);
}
dfs1(1, 1);
for (int i = 1; i <= n; i++) {
printf("%d\n", ans[i]);
}
return 0;
}
文章作者: RiverFun
文章链接: https://stevebraveman.github.io/blog/2019/11/10/112/
版权声明: 本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 RiverFun

评论