Add on a Tree: Revolution【Codeforces1189 D2】

Codeforces Round #572 (Div. 2) D2


D2. Add on a Tree: Revolution
time limit per test

1 second

memory limit per test

256 megabytes

input

standard input

output

standard output

Note that this is the second problem of the two similar problems. You can hack this problem if you solve it. But you can hack the previous problem only if you solve both problems.

You are given a tree with ?n nodes. In the beginning, 00 is written on all edges. In one operation, you can choose any 22 distinct leaves ?u, ?vand any integer number ?x and add ?x to values written on all edges on the simple path between ?u and ?v. Note that in previous subtask ?x was allowed to be any real, here it has to be integer.

For example, on the picture below you can see the result of applying two operations to the graph: adding 22 on the path from 77 to 66, and then adding −1−1 on the path from 44 to 55.

You are given some configuration of nonnegative integer pairwise different even numbers, written on the edges. For a given configuration determine if it is possible to achieve it with these operations, and, if it is possible, output the sequence of operations that leads to the given configuration. Constraints on the operations are listed in the output format section.

Leave is a node of a tree of degree 11. Simple path is a path that doesn't contain any node twice.

Input

The first line contains a single integer ?n (2≤?≤10002≤n≤1000) — the number of nodes in a tree.

Each of the next ?−1n−1 lines contains three integers ?u, ?v, ???val (1≤?,?≤?1≤u,v≤n, ?≠?u≠v, 0≤???≤100000≤val≤10000), meaning that there is an edge between nodes ?u and ?v with ???val written on it. It is guaranteed that these edges form a tree. It is guaranteed that all ???val numbers are pairwise different and even.

Output

If there aren't any sequences of operations which lead to the given configuration, output "NO".

If it exists, output "YES" in the first line. In the second line output ?m — number of operations you are going to apply (0≤?≤1050≤m≤105). Note that you don't have to minimize the number of the operations!

In the next ?m lines output the operations in the following format:

?,?,?u,v,x (1≤?,?≤?1≤u,v≤n, ?≠?u≠v, ?x — integer, −109≤?≤109−109≤x≤109), where ?,?u,v — leaves, ?x — number we are adding.

It is guaranteed that if there exists a sequence of operations producing given configuration, then there exists a sequence of operations producing given configuration, satisfying all the conditions above.

 

  D2比之D1确实就难了不少,比赛的时候也是没有敲出来,然后补题的时候,也是一直WA2,但是列写一下,发现自己的代码的数据确实是可以过Test 2的,然后我把double去改成int类型再输出,竟然就A了,好神奇……!

  我们可以这样来想这道题,只要满足D1的条件,也就是可以随意改变之后,那么就一定是“YES”了,之后我们需要怎样去改变呢,才能让所有的边都变成我们想要的样子?

  我们要从1~N-1,改变这么多条边,我们可以看到改变“u — v”这条边,如果u、v都是叶子节点的话,那么很简单,只用改变u、v即可;但是如果u、v中u是叶子节点,而v不是呢,我们可以把v向u的反方向(也就是不经过u的方向)去找连个叶子节点(并且是一定可以找到两个叶子节点的,因为度是大于2的),然后假设这两个节点分别为fir和sec,那么我们是不是可以把u—v的边权分成两半“val / 2”(题目中又说到“ all ???val numbers are pairwise”说明说有的val都是可以被2整除的),然后我们这么改变u -- fir去加上val / 2,再v -- sec去加上val / 2,最后fir -- sec去减去val / 2岂不是就可以了。那么,另外最悲催的情况,u、v都不是叶子节点的时候,我们可以效仿刚才的做法,u出发得到的节点两个x1、x2,v出发得到的叶子节点两个y1、y2,然后我们x1 -- y1去加上val / 2,然后x2 -- y2去加上val / 2,最后,x1 -- x2减去val / 2,以及y1 -- y2去减去val / 2即可。
 

#include <iostream>
#include <cstdio>
#include <cmath>
#include <string>
#include <cstring>
#include <algorithm>
#include <limits>
#include <vector>
#include <stack>
#include <queue>
#include <set>
#include <map>
#define lowbit(x) ( x&(-x) )
#define pi 3.141592653589793
#define e 2.718281828459045
#define INF 0x3f3f3f3f
#define HalF (l + r)>>1
#define lsn rt<<1
#define rsn rt<<1|1
#define Lson lsn, l, mid
#define Rson rsn, mid+1, r
#define QL Lson, ql, qr
#define QR Rson, ql, qr
#define myself rt, l, r
#define MP(a, b) make_pair(a, b)
#define MP3(a, b, c) MP(MP(a, b), c)
using namespace std;
typedef unsigned long long ull;
typedef long long ll;
const int maxN = 1e5 + 7;
int N, du[maxN], head[maxN], cnt;
vector<pair<pair<int, int>, int>> ans;
struct Eddge
{
    int nex, to;
    int val;
    Eddge(int a=-1, int b=0, int c=0):nex(a), to(b), val(c) {}
}edge[maxN<<1];
inline void addEddge(int u, int v, int val)
{
    edge[cnt] = Eddge(head[u], v, val);
    head[u] = cnt++;
}
inline void _add(int u, int v, int val) { addEddge(u, v, val); addEddge(v, u, val); }
pair<pair<int, int>, int> path[maxN];
inline int dfs(int u, int fa)
{
    if(du[u] == 1) return u;
    else
    {
        for(int i=head[u], v; ~i; i=edge[i].nex)
        {
            v = edge[i].to;
            if(v == fa) continue;
            else return dfs(v, u);
        }
    }
    return u;
}
inline void init()
{
    cnt = 0;
    memset(head, -1, sizeof(head));
}
int main()
{
    scanf("%d", &N);
    init();
    for(int i=1, u, v; i<N; i++)
    {
        int w;
        scanf("%d%d%d", &u, &v, &w);
        _add(u, v, w);
        du[u]++; du[v]++;
        path[i] = MP3(u, v, w);
    }
    for(int i=1; i<=N; i++) if(du[i] == 2) { printf("NO\n"); return 0; }
    printf("YES\n");
    for(int i=1, u, v; i<N; i++)
    {
        tie(u, v) = path[i].first;  //u、v就是path[i]的u、v
        pair<int, int> UU = {-1, -1};
        for(int j=head[u], tv; ~j; j=edge[j].nex)
        {
            tv = edge[j].to;
            if(tv == v) continue;
            int tmp = dfs(tv, u);
            if(UU.first == -1) UU.first = tmp;
            else if(UU.second == -1) { UU.second = tmp; break; }
        }
        pair<int, int> VV = {-1, -1};
        for(int j=head[v], tu; ~j; j=edge[j].nex)
        {
            tu = edge[j].to;
            if(tu == u) continue;
            int tmp = dfs(tu, v);
            if(VV.first == -1) VV.first = tmp;
            else if(VV.second == -1) { VV.second = tmp; break; }
        }
        if(du[u] == 1) UU = {u, u};
        if(du[v] == 1) VV = {v, v};
        int real = path[i].second / 2;
        ans.push_back(MP3(UU.first, VV.first, real));
        ans.push_back(MP3(UU.second, VV.second, real));
        if(UU.first != UU.second) ans.push_back(MP3(UU.first, UU.second, -real));
        if(VV.first != VV.second) ans.push_back(MP3(VV.first, VV.second, -real));
    }
    printf("%d\n", (int)ans.size());
    for(int i=0; i<ans.size(); i++) printf("%d %d %d\n", ans[i].first.first, ans[i].first.second, ans[i].second);
    return 0;
}

 

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Wuliwuliii

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值