首页 > 其他分享 >2024ICPC武汉邀请赛E. Boomerang 题解

2024ICPC武汉邀请赛E. Boomerang 题解

时间:2024-06-01 13:23:09浏览次数:20  
标签:std 2024ICPC int 题解 top dep siz Boomerang adj

E - Boomerang(动态维护树的直径 + 二分)

分析

代码实现

#include <bits/stdc++.h>
#ifdef LOCAL
#include "algo/debug.h"
#else
#define debug(...) 42
#endif
#define int long long
using Edge = int;
struct HLD {
	int n, times = 0;
	std::vector<int> siz, top, dep, fa, in, out, seq;
	std::vector<std::vector<Edge>> adj;
	HLD(const auto &adj, int root = 1) : n((int)adj.size() - 1), adj(adj) {
		siz.resize(n + 1), top.resize(n + 1), dep.resize(n + 1), in.resize(n + 1), out.resize(n + 1), seq.resize(n + 1), fa.resize(n + 1);
        dep[root] = 0, top[root] = root;
		dfs_siz(root), dfs_hld(root);
    }
	void dfs_siz(int u) {
		if (fa[u] != 0) {
			adj[u].erase(std::find(adj[u].begin(), adj[u].end(), fa[u]));
		}
		siz[u] = 1;
		for (auto &v : adj[u]) {
			fa[v] = u;
			dep[v] = dep[u] + 1;
			dfs_siz(v);
			siz[u] += siz[v];
			if (siz[v] > siz[adj[u][0]]) {
                std::swap(v, adj[u][0]);
            }
		}
	}
	void dfs_hld(int u) {
		in[u] = ++ times;
		seq[in[u]] = u;
		for (auto v : adj[u]) {
			top[v] = v == adj[u][0] ? top[u] : v;
			dfs_hld(v);
		}	
		out[u] = times;
	}
	int lca(int u, int v) {
		while (top[u] != top[v]) {
            dep[top[u]] > dep[top[v]] ? u = fa[top[u]] : v = fa[top[v]];
        }
		return dep[u] < dep[v] ? u : v;
	}
	int dist(int u, int v) { return dep[u] + dep[v] - 2 * dep[(lca(u, v))]; }
};
struct DSU {
    std::vector<int> p, siz;
    DSU(int n) : p(n), siz(n, 1) { std::iota(p.begin(), p.end(), 0); }
    int leader(int x) {
        while (x != p[x]) x = p[x] = p[p[x]];
        return x;
    }
    bool same(int x, int y) { return leader(x) == leader(y); }
    bool merge(int x, int y) {
        x = leader(x), y = leader(y);
        if (x == y) return false;
        siz[x] += siz[y], p[y] = x;
        return true;
    }
    int size(int x) { return siz[leader(x)]; }
};
main() {
    std::cin.tie(nullptr)->sync_with_stdio(false);
    int n;
    std::cin >> n;
    std::vector<std::vector<int>> g(n + 1);
    for (int i = 0; i < n - 1; ++i) {
        int a, b;
        std::cin >> a >> b;
        g[a].emplace_back(b);
        g[b].emplace_back(a);
    }
    int r, t0;
    std::cin >> r >> t0;
    HLD hld(g, r);
    DSU dsu(n + 1);
    std::vector<int> ord(n + 1);
    std::iota(ord.begin(), ord.end(), 0);
    std::sort(ord.begin(), ord.end(), 
        [&](int x, int y) {
            return hld.dep[x] < hld.dep[y];
        });
    std::vector<std::array<int, 2>> f(n + 1);
    for (int i = 1; i <= n; ++i) {
        f[i] = {i, i};
    }
    int max = 0;
    auto add = [&](int a, int b) {
        a = dsu.leader(a), b = dsu.leader(b);
        std::vector<int> p{f[a][0], f[a][1], f[b][0], f[b][1]};
        std::array<int, 2> res;
        int maxd = -1;
        for (int i = 0; i < 4; ++i) {
            for (int j = i + 1; j < 4; ++j) {
                int dist = hld.dist(p[i], p[j]);
                if (dist > maxd) {
                    res = {p[i], p[j]};
                    maxd = dist;
                }
            }
        }
        max = std::max(max, maxd);
        dsu.merge(a, b);
        f[dsu.leader(a)] = res;
    };
    int mdep = hld.dep[ord[n]];
    debug(mdep);
    std::vector<int> dia(mdep + 1);
    for (int depth = 1, idx = 2; depth <= mdep; ++depth) {
        while (idx <= n && hld.dep[ord[idx]] == depth) {
            add(r, ord[idx]);
            dia[depth] = std::max(dia[depth], max);
            idx += 1;
        }
    }
    debug(dia);
    std::vector<int> ans(n + 1);
    for (int k = 1; k <= n; ++k) {
        auto check = [&](int times) {
            int depth = std::min(mdep, times);
            int radius = (dia[depth] + 1) / 2;
            return k * (times - t0) >= radius;
        };
        int l = t0, r = 2 * n + 1;
        while (l < r) {
            int mid = l + r >> 1;
            if (check(mid)) {
                r = mid;
            } else {
                l = mid + 1;
            }
        }
        ans[k] = r;
    }
    for (int i = 1; i <= n; ++i) {
        std::cout << ans[i] << " \n"[i == n];
    }
}

标签:std,2024ICPC,int,题解,top,dep,siz,Boomerang,adj
From: https://www.cnblogs.com/sleeeeeping/p/18225584

相关文章

  • ARC119F 题解
    blog。被自动机做法恶心到了,现在也来恶心一下大家。\(\color{red}\textbf{以下内容强烈建议自己推一遍,几乎一半是重复的,推完会很爽,并且理解会很深。}\)\(\color{red}\textbf{以下内容不建议用}\LaTeX\textbf{书写,因为写起来像在吃大便。}\)暴力\(dp_{i,a,b}\)表示当前在\(......
  • 【题解】UOJ#284 快乐游戏鸡
    题目大意给出一棵有\(n\)个节点的树,编号为\(i\)的点权为\(w_i\),在树上通过一条边需要花费时间\(1\),如果能通过一个点权为\(w_i\)的点当且仅当此时的死亡次数大于等于\(w_i\),否则会立即回到起点并且死亡次数加一。给出\(q\)组询问,每组询问给出起点\(s\)和终点\(t\),......
  • CF1981D题解
    CF1981D题解前言标签:筛法,欧拉回路。赛后过的,构造一眼秒,欧拉图写错了,多少有点抽象。题意构造一个长度为\(n\)的序列\(a\),需要满足:\(\forall1\lei\len\),\(1\lea_i\le3\times10^5\)。\(\forall1\lei<j<n\),\(a_i\timesa_{i+1}\nea_j\timesa_{j+1}\)。......
  • 题解合集
    CF1270FAwesomeSubstringsCF1860CGameonPermutationP10161[DTCPC2024]小方的疑惑10P10236[yLCPC2024]D.排卡P10368「LAOI-4」ColorsP10369「LAOI-4」MexTower(Easyver.)P10370「LAOI-4」MexTower(Hardver.)P2398GCDSUMP2568GCDP8445射命丸文的取材......
  • CF Round946(div3) 题解
    目录946(div3)ABCDEG946(div3)A每个屏幕3X5,可放2个2X2,其余可填7个1X1先算2X2需要多少个屏幕,再算当前屏幕是否可放下所有1X1,根据1X1的量加屏幕.voidfunc(){ inta,b; cin>>a>>b; intans=(b+1)/2; intstp=a-(ans*15-4*b); if(stp>0) ans+=(s......
  • P2215 [HAOI2007] 上升序列题解
    题目大意对于一个集合$S$,对于$S$中长度为$m$的子序列$P$,在集合$P$中如果$P_1<P_2<...<P_m$那么我们称$P$为$S$的一个上升序列。如果有多个$P$满足条件我们就输出最小的那个,如果没有完成条件的$P$则输出Impossible。思路对于一个含有$......
  • P2266 爱的供养题解
    题目大意给你一个矩阵$w$,大小为$n\timesm$,然后你每次都从一个宝藏点开始去走旁边$T-1$个点施法,施法过的点就不用再走了,施法不需要耗费体力但是每一次从一个点走到另一个点需要耗费的权值为这两个点的高度差,你每次可以走的方向是上下左右。求最小需要耗费的体力。......
  • P10526 [XJTUPC2024] 命令行题解
    题目大意对于一个字符串$s$在输入的最后一行读入的字符,如个字符不为$E\(,\)T\(,\)B$那么这一个字符就添加至字符串$s$的末尾。对于操作$B$那么执行删除字符串$s$的最后一个字符,如果$s$为空那么跳过这个操作。对于操作$T$找到一个以字符串......
  • P10530 [XJTUPC2024] 生命游戏 题解
    题目大意一棵树一共$n$个点如果有$k$个点与某一个点相连那么这一轮的结尾这个点就会死。思路这道题有几个坑!并没有说哪一个节点是根节点。双向边记得开双倍数组。等这一轮的点消除完了才能再次判断哪一些点可以消除。首先我们创建一个数组$Size_{n}$来......
  • CF/505/D 题解
    思路这道题的思路其实是根据样例图片来的。首先第一张:这张图片可以得知$n$个点没有环的时候最少需要$n-1$个点。再看第二张:这个图确实很难思考,但稍微思考一下如果我们把含有一个强连通分量的图变成一整个强连通图。这个图的边数不就变成$n$了吗?来推一下......