• ARC103D Distance Sums 题解


    题面

    题意

    注意到距离最大的点一定是叶子节点。

    那么按 (D_i) 从大到小枚举节点,找到它的父亲 (u),直接加一条边。注意到这种做法是必要但不充分的,于是最后再重新跑一遍换根 dp 求出距离和判断和 (D_i) 是否相等即可。

    具体的,假设当前节点为 (v),其子树大小为 (sz_v),它的父亲为 (u),那么要满足 (D_u=D_v+sz_v-(n-sz_v))。二分找到 (u) 之后要记得更新 sz[u] += sz[v]

    代码:

    #include <bits/stdc++.h>
    #define DC int T = gi <int> (); while (T--)
    #define DEBUG fprintf(stderr, "Passing [%s] line %d
    ", __FUNCTION__, __LINE__)
    #define File(x) freopen(x".in","r",stdin); freopen(x".out","w",stdout)
    #define fi first
    #define se second
    #define pb push_back
    #define mp make_pair
    
    using namespace std;
    
    typedef long long LL;
    typedef unsigned long long ULL;
    typedef pair <int, int> PII;
    typedef pair <LL, int> PLI;
    typedef pair <LL, LL> PLL;
    
    template <typename T>
    inline T gi()
    {
    	T x = 0, f = 1; char c = getchar();
    	while (c < '0' || c > '9') {if (c == '-') f = -1; c = getchar();}
    	while (c >= '0' && c <= '9') x = x * 10 + c - '0', c = getchar();
    	return f * x;
    }
    
    template <typename T>
    inline T abs(T x) {return x < 0 ? -x : x;}
    
    const int N = 100003, M = N << 1;
    
    int n;
    LL d[N];
    int sz[N];
    PLI p[N];
    vector <int> g[N];
    LL nd[N];
    int nsz[N];
    
    void dfs(int u, int f, int dis)
    {
    	nd[1] += dis, nsz[u] = 1;
    	for (auto v : g[u]) if (v != f) dfs(v, u, dis + 1), nsz[u] += nsz[v];
    }
    
    void dfs1(int u, int f) {for (auto v : g[u]) if (v != f) nd[v] = nd[u] + n - 2 * nsz[v], dfs1(v, u);}
    
    void dfs_print(int u, int f) {for (auto v : g[u]) if (v != f) printf("%d %d
    ", u, v), dfs_print(v, u);}
    
    int main()
    {
    	//freopen(".in", "r", stdin); freopen(".out", "w", stdout);
    	n = gi <int> ();
    	for (int i = 1; i <= n; i+=1) d[i] = gi <LL> (), p[i] = {d[i], i}, sz[i] = 1;
    	sort(p + 1, p + 1 + n);
    	for (int i = n; i > 1; i-=1)
    	{
    		LL tmp = p[i].fi - n + 2 * sz[p[i].se];
    		int id = lower_bound(p + 1, p + 1 + n, mp(tmp, 0)) - p;
    		if (p[id].fi != tmp) return puts("-1"), !!0;
    		g[p[i].se].pb(p[id].se), g[p[id].se].pb(p[i].se);
    		sz[p[id].se] += sz[p[i].se];
    	}
    	dfs(1, 0, 0);
    	dfs1(1, 0);
    	for (int i = 1; i <= n; i+=1) if (nd[i] != d[i]) return puts("-1"), !!0;
    	dfs_print(1, 0);
    	return !!0;
    }
    

    启发:

    • 造树题要想一些特殊情况,如叶子、重心等。
  • 相关阅读:
    [Noi2011]阿狸的打字机
    Bzoj3530: [Sdoi2014]数数
    Bzoj2037: [Sdoi2008]Sue的小球
    Bzoj4869: [Shoi2017]相逢是问候
    Bzoj1899: [Zjoi2004]Lunch 午餐
    Bzoj3884: 上帝与集合的正确用法
    UVA10692:Huge Mods
    Bzoj1009: [HNOI2008]GT考试
    Bzoj1212: [HNOI2004]L语言
    【国家集训队2012】tree(伍一鸣)
  • 原文地址:https://www.cnblogs.com/xsl19/p/arc103d.html
Copyright © 2020-2023  润新知