首页 > 其他分享 >P8934 [JRKSJ R7] TSM eerT 解题报告

P8934 [JRKSJ R7] TSM eerT 解题报告

时间:2023-01-10 11:22:05浏览次数:35  
标签:P8934 R7 int s2 s1 dep TSM 端点 直径

Description
对于一个 $n$ 个结点的带边权的树 $T$,定义 $dis(x,y)$ 为 $T$ 中 $x\to y$ 路径上的边权和。再定义一个 $n$ 个结点的无向完全图 $p(T)=G$,其中 $\forall x,y\in [1,n]$,$G$ 中边 $(x,y)$ 的边权为 $dis(x,y)$。

定义 $f(T)$ 为 $p(T)$ 的最大生成树。特别的,若 $p(T)$ 的最大生成树不唯一,请立刻判断出并报告。

给定树 $T_0$ 和整数 $k$,求 $f^k(T_0)$ 。边权为正整数。

若 $\exists x\in[0,k-1]$ 使得 $p(f^x(T_0))$ 的最大生成树不唯一,输出 $-1$。否则,输出 $f^k(T_0)$ 的所有边权和对 $2^{32}$ 取模的结果。

$n\le 10^6$ ,$1\le k\le 10^7$。

Solution

赛时被 $-1$ 搞死,如果是 OI 赛制建议保证没有 $-1$。

先不考虑 $-1$ 的情况。

首先看部分分, 考虑 $k=1$ 的情况。

显然最大生成树中必然包含原树的直径,于是我们考虑跟直径有关的做法。

先求出一条直径的两条端点,然后其它点都向离它距离远的端点连边,我们便构造出了一组合法最优解。

对于 $k>1$, 我们发现做完第一次后整棵树可以看成两个端点下面挂着一堆点,然后两个端点之间连一条长度为直径的边。用队列维护一下两个部分连向父亲的值,再维护 $tag$ 标记即可。

再来看 $-1$ 的情况。

- 直径唯一。如果 $k=1$,只要看是否存在一个节点到两个端点距离相同即可,$k>1$时在模拟的过程中判断队列的前两个数是否相同,但时由于有取模,我们只能在一开始的初始值时判断

- 直径不唯一。如果所有直径都有相同的端点,并且满足直径唯一时的性质才可能有唯一解,再讨论一下即可。

具体实现看代码。

Code

#include<bits/stdc++.h>
using namespace std;
#define LL long long
#define uint unsigned int
inline int read() {
    int x = 0, f = 1; char c = getchar();
    while (c < '0' || c > '9') {if (c == '-') f = -f; c = getchar();}
    while (c >= '0' && c <= '9') {x = (x << 3) + (x << 1) + (c ^ 48); c = getchar();}
    return x * f;
}
const int N = 1e6 + 10;
int n, k, s, t;
int tot, head[N], ver[N<<1], Next[N<<1], edge[N<<1];
inline void add_edge(int u, int v, int w) {ver[++tot] = v; edge[tot] = w; Next[tot] = head[u]; head[u] = tot;}
LL mx, dep[N][2], d;
inline void dfs(int u, int fa, int p) {
    if (!fa) dep[u][p] = 0;
    for (int i = head[u]; i; i = Next[i]) {
        int v = ver[i], w = edge[i]; if (v == fa) continue;
        dep[v][p] = dep[u][p] + w; dfs(v, u, p);
    }
}
vector<LL> s1, s2;
queue<uint> q1, q2;
uint tag1, tag2, D, ans;
inline bool cmp(LL x, LL y) {return x > y;}
int main () {
    n = read(); k = read();
    for (int i = 2; i <= n; ++ i) {
        int f = i - read(), w = read();
        add_edge(f, i, w); add_edge(i, f, w);
    }
    dfs(1, 0, 0); // 第一次 dp 找最远点     
    for (int i = 1; i <= n; ++ i)
        if (dep[i][0] > mx) mx = dep[i][0], s = i;
    dfs(s, 0, 0);
    for (int i = 1; i <= n; ++ i)
        if (dep[i][0] > d) d = dep[i][0], t = i;
    dfs(t, 0, 1); // s 和 t 为其中一条直径
    bool flag1 = 0, flag2 = 0;
    for (int i = 1; i <= n; ++ i) {
        if (i == s || i == t) continue;
        if (dep[i][0] == dep[t][0]) flag1 = 1; // 还有以 s 为端点的直径
        if (dep[i][1] == dep[s][1]) flag2 = 1; // 还有以 t 为端点的直径 
    } 
    if (flag1 && flag2 || (flag1 || flag2) && k > 1) return puts("-1"), 0;
    if (flag1) {
        for (int i = 1; i <= n; ++ i) {
            if (i == s || i == t) continue;
            if (dep[i][0] < dep[i][1]) return puts("-1"), 0;
        }
    }
    if (flag2) {
        for (int i = 1; i <= n; ++ i) {
            if (i == s || i == t) continue;
            if(dep[i][1] < dep[i][0]) return puts("-1"), 0; 
        }
    }
    for (int i = 1; i <= n; ++ i) {
        if (i == s || i == t) continue;
        if (dep[i][0] == dep[i][1]) return puts("-1"), 0;
        if (dep[i][0] > dep[i][1]) s1.push_back(dep[i][0]);
        else s2.push_back(dep[i][1]);
    }
    sort(s1.begin(), s1.end(), cmp); sort(s2.begin(), s2.end(), cmp);
    int siz1 = s1.size(), siz2 = s2.size();
    for (int i = 0; i + 1 < siz1 && i < min(siz1, k-1); ++ i)
        if (s1[i] == s1[i+1]) return puts("-1"), 0;
    for (int i = 0; i + 1 < siz2 && i < min(siz2, k-1); ++ i)
        if (s2[i] == s2[i+1]) return puts("-1"), 0;
    for (auto v : s1) q1.push((uint)v);
    for (auto v : s2) q2.push((uint)v);
    D = d;
    for (int i = 2; i <= k; ++ i) {
        uint x = 0, y = 0;
        flag1 = flag2 = 0;
        if (!q1.empty()) x = q1.front() + tag1, q1.pop(), flag1 = 1;
        if (!q2.empty()) y = q2.front() + tag2, q2.pop(), flag2 = 1;
        if (flag1) q1.push(-tag1), tag1 += y + D;
        if (flag2) q2.push(-tag2), tag2 += x + D;
        D += x + y;
    }
    while (!q1.empty()) ans += q1.front() + tag1, q1.pop();
    while (!q2.empty()) ans += q2.front() + tag2, q2.pop();
    ans += D; printf("%u\n", ans);
    return 0;
}
View Code

 

标签:P8934,R7,int,s2,s1,dep,TSM,端点,直径
From: https://www.cnblogs.com/CikL1099/p/17039619.html

相关文章

  • P8932 [JRKSJ R7] Clock Paradox 题解
    在洛谷上阅读Part0题意简述原题这场月赛我唯一AC的题给出一个字符串\(S\),令\(T=S\),求使用\(S\)的子串插入\(T\),将\(T\)变形的最少的操作次数。且字符串\(S\)......
  • 应用笔记 | TSMaster使用教程—UDS刷写流程
    今天给大家介绍基于TSMaster的UDS诊断刷写流程。基本流程主要分为基本参数配置、刷写流程两部分。一、基本参数配置1、新建工程打开TSMaster软件,选择创建新工程-诊断-UDS诊......
  • 总线工具软件TSMaster使用教程之UDS刷写流程
    今天给大家介绍基于TSMaster的UDS诊断刷写流程。基本流程主要分为基本参数配置、刷写流程两部分。一、基本参数配置1、新建工程打开TSMaster软件,选择创建新工程-诊断-UDS诊......
  • thinkbook14+ R76800h 共用内存2g,导致内存小的问题
    很简单,但是问了好几遍客户也没有给到关键的有用的信息,就是在bois中可用选择集成显卡的内存大小,把2g更换成512就够了(看个人需求,我用来编码,不打游戏,需要更多的内......
  • R7-3 汉诺(Hanoi)塔问题
    R7-3汉诺(Hanoi)塔问题分数 20全屏浏览题目切换布局作者 张高燕单位 浙大城市学院古代某寺庙中有一个梵塔,塔内有3个座A、B和C,座A上放着64......
  • R7-1 字符排队
    R7-1字符排队分数 15全屏浏览题目切换布局作者 颜晖单位 浙大城市学院本题要求编写程序,将给定字符串中的字符,按照ASCII码顺序从小到大排......
  • R7-3 十六进制字符串转换成十进制非负整数
    R7-3十六进制字符串转换成十进制非负整数分数 15全屏浏览题目切换布局作者 颜晖单位 浙大城市学院输入一个以#结束的字符串,滤去所有的非......
  • R7-1 判断回文字符串
    R7-1判断回文字符串分数 15全屏浏览题目切换布局作者 颜晖-历年试卷单位 浙大城市学院输入一个字符串,判断该字符串是否为回文。回文就是......
  • R7-1 求10个点到原点的距离和
    R7-1求10个点到原点的距离和分数 15全屏浏览题目切换布局作者 张高燕单位 浙大城市学院求10个点到原点的距离和。输入10个点的坐标,计算......
  • R7-7 调查电视节目受欢迎程度
    R7-7调查电视节目受欢迎程度分数 15全屏浏览题目切换布局作者 颜晖单位 浙大城市学院某电视台要调查观众对该台8个栏目(设相应栏目编号为......