【IOI2020国家集训队作业 Part 1】CF516D Drazil and Morning Exercise

题目

展开
题目描述
Drazil and Varda are the earthworm couple. They want to find a good place to bring up their children. They found a good ground containing nature hole. The hole contains many rooms, some pairs of rooms are connected by small tunnels such that earthworm can move between them.

Let’s consider rooms and small tunnels as the vertices and edges in a graph. This graph is a tree. In the other words, any pair of vertices has an unique path between them.

Each room that is leaf in the graph is connected with a ground by a vertical tunnel. Here, leaf is a vertex that has only one outgoing edge in the graph.

Each room is large enough only to fit one earthworm living in it. Earthworm can’t live in a tunnel.

Drazil and Varda have a plan to educate their children. They want all their children to do morning exercises immediately after getting up!

When the morning is coming, all earthworm children get up in the same time, then each of them chooses the farthest path to the ground for gathering with others (these children are lazy, so they all want to do exercises as late as possible).

Drazil and Varda want the difference between the time first earthworm child arrives outside and the time the last earthworm child arrives outside to be not larger than ll (otherwise children will spread around the ground and it will be hard to keep them exercising together).

Also, The rooms that are occupied by their children should form a connected set. In the other words, for any two rooms that are occupied with earthworm children, all rooms that lie on the path between them should be occupied with earthworm children too.

How many children Drazil and Varda may have at most in order to satisfy all conditions above? Drazil and Varda want to know the answer for many different choices of ll .

(Drazil and Varda don’t live in the hole with their children)

输入格式
The first line contains one integer nn denoting how many rooms there are in the hole ( 2<=n<=10^{5}2<=n<=10
5
).

Then there are n-1n−1 lines following. Each of these lines contains three integers xx , yy , vv ( 1<=x,y<=n1<=x,y<=n , 1<=v<=10^{6}1<=v<=10
6
) denoting there is a small tunnel between room xx and room yy that takes time vv to pass.

Suppose that the time for an earthworm to get out to the ground from any leaf room is the same.

The next line contains an integer qq ( 1<=q<=501<=q<=50 ), denoting the number of different value of ll you need to process.

The last line contains qq numbers, each number denoting a value of ll ( 1<=l<=10^{11}1<=l<=10
11
).

输出格式
You should print qq lines. Each line should contain one integer denoting the answer for a corresponding value of ll .

题意翻译
给定一棵 nn 个点的树,边有边权。
定义 f_x = \max_{i=1}^n \text{dist}(x,i)f
x

=max
i=1
n

dist(x,i)。
qq 次询问最大的满足 \max_{x \in s} f_x - \min_{x \in s} f_x \le lmax
x∈s

f
x

−min
x∈s

f
x

≤l 的连通块 ss 包含的点数。
n \le 10^5n≤10
5
,q \le 50q≤50。
输入输出样例
输入 #1复制
5
1 2 3
2 3 4
4 5 3
3 4 2
5
1 2 3 4 5
输出 #1复制
1
3
3
3
5
输入 #2复制
12
5 9 3
2 1 7
11 7 2
6 5 5
2 5 3
6 7 2
1 4 4
8 5 7
1 3 8
11 12 3
10 8 2
10
13 14 14 13 13 4 6 7 2 1
输出 #2复制
10
10
10
10
10
3
3
5
2
1
说明/提示
For the first sample the hole looks like the following. Rooms 1 and 5 are leaves, so they contain a vertical tunnel connecting them to the ground. The lengths of farthest path from rooms 1–51–5 to the ground are 12,9,7,9,1212,9,7,9,12 respectively.

If l = 1, we may only choose any single room.

If l = 2…4, we may choose rooms 2, 3, and 4 as the answer.

If l = 5, we may choose all rooms.

思路

首先我们通过预处理可以求出每一个点的ff。

考虑到能更新一个点的ff的点一定会是一条直径的两个端点,因此我们找出直径后两遍dfs来求ff数组即可。

继续挖掘性质,发现这个ff值是具有单调性的,换而言之,如果我们钦定直径的中点作为根节点,那么每颗子树的ff都具有小根堆的性质。

这样我们考虑从大到小枚举连通块中最小的ff,twopointer做一下就可以了,统计连通块大小用并查集维护即可。

考虑这样做为什么是对的呢,根据小根堆性质,如果一个点被删除了,那么它的子树中所有点都会被删除,因此我们就保证了联通的单调性,删除直接在并查集的siz减一即可。

代码

#include <bits/stdc++.h>
using namespace std;

typedef long long ll;

int gi()
{
    char c = getchar();
    while(c < '0' || c > '9') c = getchar();
    int sum = 0;
    while('0' <= c && c <= '9') sum = sum * 10 + c - 48, c = getchar();
    return sum;
}

ll gl()
{
    char c = getchar();
    while(c < '0' || c > '9') c = getchar();
    ll sum = 0;
    while('0' <= c && c <= '9') sum = sum * 10 + c - 48, c = getchar();
    return sum;
}

const int maxn = 100005;

int n, ans;

struct edge
{
    int to, next, w;
} e[maxn * 2];
int h[maxn], tot, rt, fa[maxn], p[maxn], siz[maxn], vis[maxn];
ll dis[maxn], d[maxn];

void add(int w, int u, int v)
{
    e[++tot] = (edge) {v, h[u], w}; h[u] = tot;
    e[++tot] = (edge) {u, h[v], w}; h[v] = tot;
}                                               

void dfs(int u, int fa)
{
    d[u] = max(d[u], dis[u]);
    if (dis[u] > dis[rt]) rt = u;
    for (int i = h[u], v; v = e[i].to, i; i = e[i].next)
        if (v != fa) dis[v] = dis[u] + e[i].w, dfs(v, u);
}

int find(int x)
{
    if (fa[x] == x) return x;
    return fa[x] = find(fa[x]);
}

void merge(int x, int y)
{
    x = find(x); y = find(y);
    if (x == y) return ;
    if (siz[y] > siz[x]) swap(x, y);
    siz[x] += siz[y]; ans = max(ans, siz[x]); fa[y] = x;
}

int main()
{
    n = gi(); ++n; --n;
    for (int i = 1; i < n; ++i) add(gi(), gi(), gi());

    dfs(1, 0);
    int tmp = rt; dis[rt] = 0; rt = 0;
    dfs(tmp, 0);
    dis[rt] = 0; dfs(rt, 0);

    for (int i = 1; i <= n; ++i) p[i] = i;
    sort(p + 1, p + n + 1, [](const int &a, const int &b) {return d[a] < d[b];});
    int q = gi();
    ll lim;
    while (q--) {
        lim = gl();
        for (int i = 1; i <= n; ++i) fa[i] = i, siz[i] = 1, vis[i] = 0;

        ans = 1;
        for (int k = n, j = n; k >= 1; --k) {
            while (d[p[j]] > d[p[k]] + lim) {
                --siz[find(p[j])];
                --j;
            }
            vis[p[k]] = 1;
            for (int i = h[p[k]], v; v = e[i].to, i; i = e[i].next)
                if (vis[v]) merge(p[k], v);
        }
        printf("%d\n", ans);
    }

    return 0;
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值