题意:给你一颗树,树的边权都是偶数,并且边权各不相同。你可以选择树的两个叶子结点,并且把两个叶子结点之间的路径加上一个值(可以为负数),问是否可以通过这种操作构造出这颗树?如果可以,输出构造方案。初始树的边权都是0。

思路:A1很简单,只要判断是否有度数为2的点就可以了。对于A2, 由于边权各不相同,所以A1的结论同样适用。现在我们来构造一组答案。官方题解的构造方式是这样的:我们假设要让一个节点u到叶子结点v的路径都加上一个值x,并且知道叶子结点l1, l2都可以到达u,我们执行以下操作:v到l1的路径加上x / 2, v到l2的路径加上x / 2, l1 到 l2的路径加上-x / 2,这样除了u到v的路径,其它路径的值没有变(太菜了,想不到。。。)。那么,我们从树根开始,从上到下逐个构造边权即可。

由于n只有1000,所以实现方式有两种。

第一种很暴力,赋值操作直接暴力加,复杂度O(n ^ 2)。

代码:

#include <bits/stdc++.h>
#define pii pair<int, int>
#define LL long long
using namespace std;
const int maxn = 1010;
vector<pii> G[maxn];
vector<int> son[maxn];
LL add[maxn];
struct node {int x, y;LL z;
};
vector<node> ans;
int root = 1;
int f[maxn];
void adde(int x, int y, int z) {G[x].push_back(make_pair(y, z));G[y].push_back(make_pair(x, z));
}int dfs(int x, int fa) {f[x] = fa;for (auto y : G[x]) {if(y.first== fa) continue;int tmp = dfs(y.first, x);son[x].push_back(tmp);}if(G[x].size() == 1) {return x;}return son[x][0];
}void update(int x, int p, int val) {while(x != p) {add[x] += val;x = f[x];}
}
void dfs1(int x, int fa) {int cnt = 0;if(x == root) {int y = G[x][0].first;if(G[y].size() == 1) {ans.push_back((node){x, y, G[x][0].second});return;}LL tmp = G[x][0].second;ans.push_back((node){son[y][0], root, tmp / 2});ans.push_back((node){son[y][1], root, tmp / 2});ans.push_back(node{son[y][0], son[y][1], -tmp / 2});dfs1(y, x);} else {for (auto y : G[x]) {if(y.first == fa) continue;LL tmp = y.second - add[y.first];int tmp1;if(cnt == 0) tmp1 = 1;else tmp1 = 0;ans.push_back((node){son[x][cnt], root, tmp / 2});ans.push_back((node){son[x][cnt], son[x][tmp1], tmp / 2});ans.push_back(node{root, son[x][tmp1], -tmp / 2});update(son[x][cnt], x, tmp);dfs1(y.first, x);cnt++;}}
}int main() {int n;int x, y, z;scanf("%d", &n);for (int i = 1; i < n; i++) {scanf("%d%d%d", &x, &y, &z);adde(x, y, z);}for (int i = 1; i <= n; i++) {if(G[i].size() == 2) {printf("NO\n");return 0;}}for (int i = 1; i <= n; i++) {if(G[i].size() == 1) {root = i;break;}}dfs(root, -1);dfs1(root, -1);printf("YES\n");printf("%d\n", ans.size());for (int i = 0; i < ans.size(); i++) {printf("%d %d %lld\n", ans[i].x, ans[i].y, ans[i].z);}
}

第二种用了类似树剖中重儿子的思想,我们给一颗子树中决定一个优先级最高的叶子结点,这样加的操作是这个叶子结点到它的祖先的路径上进行的,其它的路径没有影响,这样累加影响的时候,如果这个叶子结点,把前面的影响累加上,否则不加。复杂度O(n)。

代码:

#include <bits/stdc++.h>
#define pii pair<int, int>
#define LL long long
using namespace std;
const int maxn = 1010;
vector<pii> G[maxn];
vector<int> son[maxn];
LL add[maxn];
struct node {int x, y;LL z;
};
vector<node> ans;
int root = 1;
int v[maxn];
void adde(int x, int y, int z) {G[x].push_back(make_pair(y, z));G[y].push_back(make_pair(x, z));
}int dfs(int x, int fa) {for (auto y : G[x]) {if(y.first== fa) continue;int tmp = dfs(y.first, x);son[x].push_back(tmp);}if(G[x].size() == 1) {v[x] = x;return x;}v[x] = son[x][0];return son[x][0];
}void dfs1(int x, int fa, int tot) {int cnt = 0;if(x == root) {int y = G[x][0].first;if(G[y].size() == 1) {ans.push_back((node){x, y, G[x][0].second});return;}LL tmp = G[x][0].second;ans.push_back((node){son[y][0], root, tmp / 2});ans.push_back((node){son[y][1], root, tmp / 2});ans.push_back(node{son[y][0], son[y][1], -tmp / 2});dfs1(y, x, 0);} else {for (auto y : G[x]) {if(y.first == fa) continue;LL tmp = y.second;if(v[y.first] == v[x]) tmp -= tot;int tmp1;if(cnt == 0) tmp1 = 1;else tmp1 = 0;ans.push_back((node){son[x][cnt], root, tmp / 2});ans.push_back((node){son[x][cnt], son[x][tmp1], tmp / 2});ans.push_back(node{root, son[x][tmp1], -tmp / 2});dfs1(y.first, x, y.second);cnt++;}}
}int main() {int n;int x, y, z;scanf("%d", &n);for (int i = 1; i < n; i++) {scanf("%d%d%d", &x, &y, &z);adde(x, y, z);}for (int i = 1; i <= n; i++) {if(G[i].size() == 2) {printf("NO\n");return 0;}}for (int i = 1; i <= n; i++) {if(G[i].size() == 1) {root = i;break;}}dfs(root, -1);dfs1(root, -1, 0);printf("YES\n");printf("%d\n", ans.size());for (int i = 0; i < ans.size(); i++) {printf("%d %d %lld\n", ans[i].x, ans[i].y, ans[i].z);}
}

两份代码中为了实现方便,都找了一个度为1的点为根。

转载于:https://www.cnblogs.com/pkgunboat/p/11145961.html

Codeforces 1188A 构造相关推荐

  1. Dividing the numbers CodeForces - 899C (构造)

    大意: 求将[1,n]划分成两个集合, 且两集合的和的差尽量小. 和/2为偶数最小差一定为0, 和/2为奇数一定为1. 显然可以通过某个前缀和删去一个数得到. #include <iostrea ...

  2. Earth Wind and Fire CodeForces - 1148E (构造)

    大意: $n$个石子, 第$i$个石子初始位置$s_i$, 每次操作选两个石子$i,j$, 要求$s_i<s_j$, 任取$d$, 满足$0\le 2d\le s_j-s_i$, 将$s_i,s ...

  3. cf1200构造15道

    最近做构造,想对比下先做后看答案归纳,留下思路之后直接看答案归纳,然后再统一检测,还有直接看答案,归纳,检测三种方法哪种效率高些,于是先做个十五题试试第一个方法,花3天写了15道构造,等到归纳的时候已 ...

  4. 构造 Codeforces Round #302 (Div. 2) B Sea and Islands

    题目传送门 1 /* 2 题意:在n^n的海洋里是否有k块陆地 3 构造算法:按奇偶性来判断,k小于等于所有点数的一半,交叉输出L/S 4 输出完k个L后,之后全部输出S:) 5 5 10 的例子可以 ...

  5. 暴力+构造 Codeforces Round #283 (Div. 2) C. Removing Columns

    题目传送门 1 /* 2 题意:删除若干行,使得n行字符串成递增排序 3 暴力+构造:从前往后枚举列,当之前的顺序已经正确时,之后就不用考虑了,这样删列最小 4 */ 5 /************* ...

  6. Codeforces 610C:Harmony Analysis(构造)

    [题目链接] http://codeforces.com/problemset/problem/610/C [题目大意] 构造出2^n个由1和-1组成的串使得其两两点积为0 [题解] 我们可以构造这样 ...

  7. CodeForces 459C(构造题)

    http://codeforces.com/problemset/problem/459/C /** 题意:有n个同学,k辆车,d天(每天n个同学去一个地方)问经过d天后,任意的多个同学不能总在一起d ...

  8. Codeforces 1276C/1277F Beautiful Rectangle (构造)

    题目链接 http://codeforces.com/contest/1276/problem/C 题解 嗯,比赛结束前3min想到做法然后rush不出来了--比赛结束后又写了15min才过-- 以下 ...

  9. Codeforces 1276C/1277F/1259F Beautiful Rectangle (构造)

    题目链接 http://codeforces.com/contest/1276/problem/C 题解 嗯,比赛结束前3min想到做法然后rush不出来了--比赛结束后又写了15min才过-- 以下 ...

最新文章

  1. Tomcat内存设置详解
  2. [CentOS Python系列] 三.阿里云MySQL数据库开启配置及SQL语句基础知识
  3. matlab组织的培训讲义,matlab培训讲义.doc
  4. readonly和const的区别
  5. ReviewForJob——快速排序(基于插入排序)+快速选择(快速排序变体)
  6. Unable to parse the date: 2017-12-30 日期格式转化失败
  7. java程序员面试怎么难为面试官_Java程序员面试这些多线程问题你知道吗?
  8. 剑指Offer之寻找链表中环的入口问题
  9. 实习踩坑之路:日期计算错误,Java8API导致Unsupported unit: Seconds,计算当前时间到凌晨00:00的计算方法
  10. 信息安全-工控安全需求分析与安全保护工程
  11. Android Camera 预览及录制视频 附demo
  12. 读书笔记——戴尔·卡耐基(美)《人性的弱点》
  13. 行业洞察系列之《事件管理的 5 个阶段及其改进建议》
  14. 【测评】国外AR平台ENTITI测评-网页编辑器(1)
  15. stm32 mbed 入门教程(一)---前期准备
  16. Android学习之SwipeRefreshLayout+RecyclerView+CardView
  17. MarkDown语法详解:标题、字体、列表、引用、图片、表格、代码、超链接、公式
  18. 关于灰度共生矩阵的一点知识(MATLAB)
  19. 迅为RK3568开发板Android11修改开机动画
  20. 虚拟机与主机之间不能复制粘贴问题

热门文章

  1. 028 -bash-4.1$ 出现故障的原理及解决办法?
  2. new和delete
  3. SQL Server 2012安装图解
  4. android 进程间通信数据(一)------parcel的起源
  5. AGS Server 10.1 切图工具
  6. C++之private虚函数
  7. explorer.exe rundll32.exe病毒解决方案
  8. EXCEL小技巧:如何统计非空单元格
  9. 自然语言交流系统 phxnet团队 创新实训 项目博客 (五)
  10. 安装MariaDB数据库(未完成)