CodeForces 516D Drazil and Morning Exercise


给你一棵树,边有边权,定义 \(f_x=\max_{i=1}^n\operatorname{dist}(x,i)\)\(q\) 次询问,每次给出一个数 \(l\) 求最大的连通块 \(s\) 满足 \(\max_{x\in s}f_x-\min_{x\in s}f_x\le l\)\(n\le 10^5,q\le 50\)

首先假设这棵树的直径的两个端点为 \(u,v\),不难发现 \(f_x=\max(\operatorname{dist}(u,x)\operatorname{v,x})\)。这个用证明直径的方法可以证明。

然后我们需要发现一个性质,那就是将点按照 \(f\) 从大到小排序,那么儿子一定排在父亲的前面。

然后就好办了,我们考虑将点按 \(f\) 从大到小排序,然后我们考虑在上面 two points,一边用并查集维护两个指针所在区间的联通性,插入一个点直接将其儿子合并,删除节点是发现只会删除叶子节点,不会改变连通性,只要把该连通块 size 减掉即可。

这里是代码

cpp
#define _CRT_SECURE_NO_WARNINGS
 
#include <map>
#include <set>
#include <stack>
#include <ctime>
#include <cmath>
#include <queue>
#include <cstdio>
#include <cctype>
#include <vector>
#include <bitset>
#include <cstdlib>
#include <cstring>
#include <cassert>
#include <fstream>
#include <iostream>
#include <algorithm>
 
using namespace std;
 
inline char gc() {
    static const int L = 233333;
    static char sxd[L], *sss = sxd, *ttt = sxd;
    if (sss == ttt) {
        ttt = (sss = sxd) + fread(sxd, 1, L, stdin);
        if (sss == ttt) {
            return EOF;
        }
    }
    return *sss++;
}
 
#ifndef _AT_HOME
#define dd c = gc()
#else
#define dd c = getchar()
#endif
inline char readalpha() {
    char dd;
    for (; !isalpha(c); dd);
    return c;
}
 
inline char readchar() {
    char dd;
    for (; c == ' '; dd);
    return c;
}
 
template <class T>
inline bool read(T& x) {
    bool flg = false;
    char dd;
    x = 0;
    for (; !isdigit(c); dd) {
        if (c == '-') {
            flg = true;
        } else if(c == EOF) {
            return false;
        }
    }
    for (; isdigit(c); dd) {
        x = (x * 10) + (c ^ 48);
    }
    if (flg) {
        x = -x;
    }
    return true;
}
#undef dd
 
template <class T>
inline void write(T x) {
    if (x < 0) {
        putchar('-');
        x = -x;
    }
    if (x < 10) {
        putchar(x | 48);
        return;
    }
    write(x / 10);
    putchar((x % 10) | 48);
}
 
template <class T>
inline void writesp(T x) {
    write(x);
    putchar(' ');
}
 
template <class T>
inline void writeln(T x) {
    write(x);
    puts("");
}
 
#define lowbit(x) (x & -x)
 
namespace dfcmd {
    
    const int maxn = 100005;
 
    typedef long long LL;
 
    int n, q;
 
    struct Edge {
        int to, nxt;
        LL dist;
    } e[maxn << 1];
 
    int first[maxn];
 
    inline void add_edge(int from, int to, LL dist) {
        static int cnt = 0;
        e[++cnt].nxt = first[from];
        first[from] = cnt;
        e[cnt].to = to;
        e[cnt].dist = dist;
        e[++cnt].nxt = first[to];
        first[to] = cnt;
        e[cnt].to = from;
        e[cnt].dist = dist;
    }
 
    LL v[maxn];
    int vis[maxn];
 
    inline int bfs(int from) {
        memset(vis, 0, sizeof(vis));
        queue<pair<int, LL>> q;
        q.emplace(from, 0);
        int ans = 0;
        LL dd = 0;
        while (!q.empty()) {
            int now = q.front().first;
            LL d = q.front().second;
            q.pop();
            vis[now] = 1;
            if (d > dd) {
                dd = d;
                ans = now;
            }
            v[now] = max(v[now], d);
            for (int i = first[now]; i; i = e[i].nxt) {
                int to = e[i].to;
                if (!vis[to]) {
                    q.emplace(to, d + e[i].dist);
                }
            }
        }
        return ans;
    }
 
    inline void getrt() {
        bfs(bfs(bfs(1)));
    }
 
    int rt;
    LL l;
 
    int no[maxn];
 
    inline bool cmp(int x, int y) {
        return v[x] < v[y];
    }
 
    namespace DFCDM {
 
        int fa[maxn];
        int siz[maxn];
        int Fa[maxn];
 
        inline int getfa(int x) {
            return fa[x] == x ? x : fa[x] = getfa(fa[x]);
        }
 
        inline void dfs(int now) {
            for (int i = first[now]; i; i = e[i].nxt) {
                int to = e[i].to;
                if (to != Fa[now]) {
                    Fa[to] = now;
                    dfs(to);
                }
            }
        }
 
        inline int solve() {
            for (int i = 1; i <= n; ++i) {
                fa[i] = i;
                siz[i] = 1;
            }
            int ans = 0;
            for (int rr = n, ll = n; rr; --rr) {
                while (ll - 1 && v[no[rr]] - v[no[ll - 1]] <= l) {
                    ll--;
                    for (int i = first[no[ll]]; i; i = e[i].nxt) {
                        int to = e[i].to;
                        if (to != Fa[no[ll]]) {
                            int fax = getfa(no[ll]);
                            int fay = getfa(to);
                            fa[fay] = fax;
                            siz[fax] += siz[fay];
                        }
                    }
                    ans = max(ans, siz[getfa(no[ll])]);
                }
                siz[getfa(no[rr])]--;
            }
            return ans;
        }
 
    }
 
    int Main() {
        read(n);
        for (int i = 1; i < n; ++i) {
            int u, v;
            LL d;
            read(u), read(v), read(d);
            add_edge(u, v, d);
        }
        getrt();
        for (int i = 1; i <= n; ++i) {
            no[i] = i;
        }
        sort(no + 1, no + n + 1, cmp);
        DFCDM::dfs(no[1]);
        read(q);
        while (q--) {
            read(l);
            writeln(DFCDM::solve());
        }
        return 0;
    }
 
}
 
int main() {
    return dfcmd::Main();
}

Cite this post

@misc{pu2020oiicpccodeforcescf516d,
  author = {Pu, Fanyi},
  title  = {CodeForces 516D Drazil and Morning Exercise},
  year   = {2020},
  month  = {2},
  url    = {https://pufanyi.com/blog/oi-icpc/codeforces/cf516d}
}