P4556 [Vani有约会]雨天的尾巴
\(n\) 座房屋,并形成一个树状结构。然后救济粮分\(m\) 次发放,每次选择两个房屋 \((x,y)\),然后对于 \(x\)到\(y\)的路径上(含\(x\)和\(y\))每座房子里发放一袋 \(z\) 类型的救济粮。
然后深绘里想知道,当所有的救济粮发放完毕后,每座房子里存放的最多的是哪种救济粮。
紫色的板子,水题\(+1\)
每个节点维护一棵权值线段树,下标为救济粮种类,区间维护数量最多的救济粮编号。
然后树上点差分思想,最后统计时自底向上做树上前缀和、线段树合并即得当前节点信息。
/**
*@ author:pyyyyyy/guhl37
*@ bolg:https://www.cnblogs.com/pyyyyyy
*@ Debug:
**/
#include <bits/stdc++.h>
using namespace std;
const int N = 4000045;
const int Log = 20;
struct Edeg{
int v, Next;
}e[N];
int head[N], ecnt, cnt;
void add(int u,int v){
e[++ecnt].Next = head[u];
head[u] = ecnt;
e[ecnt].v = v;
}
struct SegmentTree
{
int ls, rs;
int dat, pos;
}t[N << 2];
int root[N], num;
int f[N][21], dep[N], ans[N];
int n, m, val[N], X[N], Y[N], Z[N];
void dfs(int u, int fa){
f[u][0] = fa;
dep[u] = dep[fa] + 1;
for(int i = 1; i <= Log; ++i)
f[u][i] = f[f[u][i - 1]][i - 1];
for(int i = head[u]; i; i = e[i].Next){
int to = e[i].v;
if(to == fa) continue;
dfs(to, u);
}
}
int lca(int x,int y){
if(dep[x] < dep[y]) swap(x, y);
for(int i = Log -1; i >= 0; --i)
if(dep[f[x][i]] >= dep[y]) x = f[x][i];
if(x == y) return x;
for(int i = Log -1; i >= 0; --i)
if(f[x][i] != f[y][i]) x = f[x][i], y = f[y][i];
return f[x][0];
}
void insert(int p, int l, int r, int val, int delta){
if(l == r){
t[p].dat += delta;
t[p].pos = t[p].dat ? l : 0;
return ;
}
int mid = (l + r) >> 1;
if(val <= mid) {
if(!t[p].ls) t[p].ls = ++num;
insert(t[p].ls, l, mid, val, delta);
}
else{
if(!t[p].rs) t[p].rs = ++num;
insert(t[p].rs, mid + 1, r, val, delta);
}
t[p].dat = max(t[t[p].ls].dat, t[t[p].rs].dat);
t[p].pos = t[t[p].ls].dat >= t[t[p].rs].dat ? t[t[p].ls].pos : t[t[p].rs].pos;
}
int merge(int p, int q, int l, int r){
if(!p) return q;
if(!q) return p;
if(l == r){
t[p].dat += t[q].dat;
t[p].pos = t[p].dat ? l : 0;
return p;
}
int mid = (l + r) >> 1;
t[p].ls = merge(t[p].ls, t[q].ls, l, mid);
t[p].rs = merge(t[p].rs, t[q].rs, mid + 1, r);
t[p].dat = max(t[t[p].ls].dat, t[t[p].rs].dat);
t[p].pos = t[t[p].ls].dat >= t[t[p].rs].dat ? t[t[p].ls].pos : t[t[p].rs].pos;
return p;
}
void search(int x){
for(int i = head[x]; i; i = e[i].Next){
int to = e[i].v;
if(dep[to] <= dep[x]) continue;
search(to);
root[x] = merge(root[x], root[to], 1, cnt);
}
ans[x] = t[root[x]].pos;
}
int main()
{
// freopen("input.in","r",stdin);
// freopen(".out","w",stdout);
cin >> n >> m;
for(int i = 1; i < n; ++i){
int x, y;
scanf("%d %d",&x, &y);
add(x, y);add(y, x);
}
dfs(1, 0);
// for(int i = 1; i <= n; ++i) cout << dep[i] << ' ';
// cout<<endl;
for(int i = 1; i <= n; ++i) root[i] = ++num;
for(int i = 1; i <= m; ++i) {
scanf("%d %d %d",&X[i], &Y[i], &Z[i]);
val[i] = Z[i];
}
sort(val + 1, val + m + 1);
cnt = unique(val + 1, val + m + 1) - val - 1;
for(int i = 1; i <= m; ++i){
int x = X[i], y = Y[i];
int z = lower_bound(val + 1, val + cnt, Z[i]) - val;
int p = lca(x, y);
// cout << z << '\n';
// cout << x << ' ' << y << ' ' << p << '\n';
insert(root[x], 1, cnt, z, 1);
insert(root[y], 1, cnt, z, 1);
insert(root[p], 1, cnt, z, -1);
if(f[p][0]) insert(root[f[p][0]], 1, cnt, z, -1);
}
search(1);
// for(int i = 1; i <= n; ++i) cout << ans[i] << ' ';
// cout<<endl;
for(int i = 1; i <= n; ++i) printf("%d\n", val[ans[i]]);
return 0;
}
$$Life \quad is \quad fantastic!$$