【JZOJ3397】【GDOI2014模拟】雨天的尾巴
题目大意
给你一棵个点的树,有个操作,每次操作将到的路径上的每个点都放入一个颜色为的球。你需要求出最后每个点里个数最多的球是哪种颜色的。
分析
通过树链剖分把树上路径转化为若干区间,把树上问题转化为区间问题,然后结合差分思想,在左端点加上标记,在右端点的位置加上标记,我们从左往右做,用线段树维护当前出现次数最多的颜色,时间复杂度。最好将颜色离散化,这样线段树就不必动态开点了。
Code
#include <vector>
#include <cstdio>
#include <cstring>
#include <algorithm>
#define lson rt << 1
#define rson rt << 1 | 1
using namespace std;
const int N = 100007;
int n, m, len, x[N], y[N], z[N], arr[N], ans[N];
int tot, cnt, st[N], to[N << 1], nx[N << 1], son[N], top[N], dfn[N], fa[N], size[N], ord[N], dep[N];
void add(int u, int v) { to[++tot] = v, nx[tot] = st[u], st[u] = tot; }
vector<int> lis[N];
void dfs(int u)
{
size[u] = 1;
for (int i = st[u]; i; i = nx[i])
if (to[i] != fa[u])
{
dep[to[i]] = dep[u] + 1, fa[to[i]] = u, dfs(to[i]), size[u] += size[to[i]];
if (size[to[i]] > size[son[u]]) son[u] = to[i];
}
}
void dfs2(int u, int tp)
{
dfn[u] = ++cnt, ord[cnt] = u, top[u] = tp;
if (son[u]) dfs2(son[u], tp);
for (int i = st[u]; i; i = nx[i]) if (to[i] != fa[u] && to[i] != son[u]) dfs2(to[i], to[i]);
}
struct note { int id, cnt; } tr[N * 4];
note max(note a, note b)
{
if (a.cnt == b.cnt) return a.id < b.id ? a : b;
return a.cnt > b.cnt ? a : b;
}
void build(int rt, int l, int r)
{
if (l == r) { tr[rt] = (note){l, 0}; return; }
int mid = l + r >> 1;
build(lson, l, mid), build(rson, mid + 1, r);
}
void ins(int rt, int l, int r, int po, int v)
{
if (l == r) { tr[rt].cnt += v; return; }
int mid = l + r >> 1;
if (po <= mid) ins(lson, l, mid, po, v);
else ins(rson, mid + 1, r, po, v);
tr[rt] = max(tr[lson], tr[rson]);
}
int main()
{
scanf("%d%d", &n, &m);
for (int i = 1, u, v; i < n; i++) scanf("%d%d", &u, &v), add(u, v), add(v, u);
dep[1] = 1, dfs(1), dfs2(1, 1);
for (int i = 1; i <= m; i++) scanf("%d%d%d", &x[i], &y[i], &z[i]), arr[++len] = z[i];
sort(arr + 1, arr + len + 1);
len = unique(arr + 1, arr + len + 1) - arr - 1;
for (int i = 1, u, v, w; i <= m; i++)
{
u = x[i], v = y[i], w = lower_bound(arr + 1, arr + len + 1, z[i]) - arr;
while (top[u] != top[v])
{
if (dep[top[u]] < dep[top[v]]) swap(u, v);
lis[dfn[top[u]]].push_back(w), lis[dfn[u] + 1].push_back(-w);
u = fa[top[u]];
}
if (dep[u] < dep[v]) swap(u, v);
lis[dfn[v]].push_back(w), lis[dfn[u] + 1].push_back(-w);
}
build(1, 1, len);
for (int i = 1; i <= n; i++)
{
int sz = lis[i].size();
for (int j = 0, k; j < sz; j++)
{
k = lis[i][j];
if (k > 0) ins(1, 1, len, k, 1);
else ins(1, 1, len, -k, -1);
}
ans[ord[i]] = arr[tr[1].cnt ? tr[1].id : 0];
}
for (int i = 1; i <= n; i++) printf("%d\n", ans[i]);
return 0;
}
作者:zjlcnblogs
出处:https://www.cnblogs.com/zjlcnblogs/p/11178605.html
版权:本作品采用「署名-非商业性使用-相同方式共享 4.0 国际」许可协议进行许可。
分类:
OI
【推荐】还在用 ECharts 开发大屏?试试这款永久免费的开源 BI 工具!
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 从问题排查到源码分析:ActiveMQ消费端频繁日志刷屏的秘密
· 一次Java后端服务间歇性响应慢的问题排查记录
· dotnet 源代码生成器分析器入门
· ASP.NET Core 模型验证消息的本地化新姿势
· 对象命名为何需要避免'-er'和'-or'后缀
· “你见过凌晨四点的洛杉矶吗?”--《我们为什么要睡觉》
· 编程神器Trae:当我用上后,才知道自己的创造力被低估了多少
· 开发的设计和重构,为开发效率服务
· 从零开始开发一个 MCP Server!
· Ai满嘴顺口溜,想考研?浪费我几个小时