using System;
using System.Collections.Generic;
using System.Linq;
class Program
{
static string InputPattern = "InputX";
static List<string> GetInputList()
{
var WillReturn = new List<string>();
if (InputPattern == "Input1") {
WillReturn.Add("3 2");
WillReturn.Add("1 2 2");
WillReturn.Add("2 3 1");
//1
//1
//0
}
else if (InputPattern == "Input2") {
WillReturn.Add("3 3");
WillReturn.Add("1 2 0");
WillReturn.Add("2 3 0");
WillReturn.Add("1 3 2");
//-1
}
else {
string wkStr;
while ((wkStr = Console.ReadLine()) != null) WillReturn.Add(wkStr);
}
return WillReturn;
}
static long mNodeCnt;
struct EdgeInfoDef
{
internal long ToNode;
internal long SumVal;
}
static Dictionary<long, List<EdgeInfoDef>> mEdgeInfoListDict = new Dictionary<long, List<EdgeInfoDef>>();
static void Main()
{
List<string> InputList = GetInputList();
long[] wkArr = { };
Action<string> SplitAct = pStr =>
wkArr = pStr.Split(' ').Select(pX => long.Parse(pX)).ToArray();
SplitAct(InputList[0]);
mNodeCnt = wkArr[0];
foreach (string EachStr in InputList.Skip(1)) {
SplitAct(EachStr);
long A = wkArr[0];
long B = wkArr[1];
long C = wkArr[2];
Action<long, long, long> AddEdgeAct = (pFromNode, pToNode, pSumVal) =>
{
if (mEdgeInfoListDict.ContainsKey(pFromNode) == false) {
mEdgeInfoListDict[pFromNode] = new List<EdgeInfoDef>();
}
EdgeInfoDef WillAdd;
WillAdd.ToNode = pToNode;
WillAdd.SumVal = pSumVal;
mEdgeInfoListDict[pFromNode].Add(WillAdd);
};
AddEdgeAct(A, B, C);
AddEdgeAct(B, A, C);
}
for (long I = 1; I <= mNodeCnt; I++) {
mNodeValInfoListDict[I] = new List<NodeValInfoDef>();
}
// ノード1からDFSを行う
ExecDFS1();
// Xの符号が同じものが複数あったら実現不可
foreach (var EachPair in mNodeValInfoListDict) {
var XSet = new HashSet<long>();
foreach (NodeValInfoDef EachNodeValInfo in EachPair.Value) {
if (XSet.Add(EachNodeValInfo.X) == false) {
Console.WriteLine(-1);
return;
}
}
}
// Xの値が特定可能な場合
foreach (var EachPair in mNodeValInfoListDict) {
if (EachPair.Value.Count == 2) {
long Uhen = 0;
foreach (NodeValInfoDef EachNodeValInfo in EachPair.Value) {
if (EachNodeValInfo.X == 1) {
Uhen -= EachNodeValInfo.Teisuu;
}
if (EachNodeValInfo.X == -1) {
Uhen += EachNodeValInfo.Teisuu;
}
}
if (Uhen % 2 == 1) {
Console.WriteLine(-1);
return;
}
if (Uhen < 0) {
Console.WriteLine(-1);
return;
}
long XVal = Uhen / 2;
// DFSを行い、十分性の確認
Dictionary<long, long> ResultDict1;
bool Result1 = ExecDFS2(1, XVal, out ResultDict1);
if (Result1) {
foreach (var EachValInfo in ResultDict1.OrderBy(pX => pX.Key)) {
Console.WriteLine(EachValInfo.Value);
}
return;
}
Console.WriteLine(-1);
return;
}
}
// Xの範囲が特定できる場合
var XList1 = new List<long>();
var XList2 = new List<long>();
foreach (var EachPair in mNodeValInfoListDict) {
NodeValInfoDef CurrNodeValInfo = EachPair.Value[0];
if (CurrNodeValInfo.X == 1) {
XList1.Add(CurrNodeValInfo.Teisuu * (-1));
}
if (CurrNodeValInfo.X == -1) {
XList2.Add(CurrNodeValInfo.Teisuu);
}
}
long RangeMin = XList1.Max();
long RangeMax = XList2.Min();
if (RangeMax < 0) {
Console.WriteLine(-1);
return;
}
long AnswerX = Math.Max(0, RangeMin);
// DFSを行い、十分性の確認
Dictionary<long, long> ResultDict2;
bool Result2 = ExecDFS2(1, AnswerX, out ResultDict2);
if (Result2) {
foreach (var EachValInfo in ResultDict2.OrderBy(pX => pX.Key)) {
Console.WriteLine(EachValInfo.Value);
}
return;
}
Console.WriteLine(-1);
return;
}
// ノード1からDFSを行う
static void ExecDFS1()
{
var Stk = new Stack<JyoutaiDef1>();
JyoutaiDef1 WillPush;
WillPush.CurrNode = 1;
Stk.Push(WillPush);
NodeValInfoDef FirstNodeValInfo;
FirstNodeValInfo.X = 1;
FirstNodeValInfo.Teisuu = 0;
mNodeValInfoListDict[1].Add(FirstNodeValInfo);
var UsedEdgeSet = new HashSet<long>();
while (Stk.Count > 0) {
JyoutaiDef1 Popped = Stk.Pop();
long CurrNode = Popped.CurrNode;
foreach (EdgeInfoDef EachEdgeInfo in mEdgeInfoListDict[CurrNode]) {
long FromNode = CurrNode;
long ToNode = EachEdgeInfo.ToNode;
long EdgeHash = GetEdgeHash(FromNode, ToNode);
if (UsedEdgeSet.Add(EdgeHash) == false) {
continue;
}
NodeValInfoDef CurrNodeValInfo = mNodeValInfoListDict[CurrNode][0];
NodeValInfoDef ToNodeValInfo;
ToNodeValInfo.X = -CurrNodeValInfo.X;
ToNodeValInfo.Teisuu = EachEdgeInfo.SumVal - CurrNodeValInfo.Teisuu;
mNodeValInfoListDict[ToNode].Add(ToNodeValInfo);
// 重複はremove
var CurrList = mNodeValInfoListDict[ToNode];
for (int I = CurrList.Count - 1; 0 <= I; I--) {
for (int J = 0; J <= I - 1; J++) {
if (CurrList[I].X == CurrList[J].X
&& CurrList[I].Teisuu == CurrList[J].Teisuu) {
CurrList.RemoveAt(I);
break;
}
}
}
WillPush.CurrNode = ToNode;
Stk.Push(WillPush);
}
}
}
struct NodeValInfoDef
{
internal long X; // Xの係数
internal long Teisuu; // 定数
}
static Dictionary<long, List<NodeValInfoDef>> mNodeValInfoListDict =
new Dictionary<long, List<NodeValInfoDef>>();
struct JyoutaiDef1
{
internal long CurrNode;
}
// DFSを行い、全てのノードを0以上にできるかを判定
static bool ExecDFS2(long pStaNode, long pStaVal, out Dictionary<long, long> pResultDict)
{
// 値[ノード]なDict
pResultDict = new Dictionary<long, long>();
pResultDict[pStaNode] = pStaVal;
var Stk = new Stack<JyoutaiDef2>();
JyoutaiDef2 WillPush;
WillPush.CurrNode = pStaNode;
WillPush.CurrVal = pStaVal;
Stk.Push(WillPush);
var UsedEdgeSet = new HashSet<long>();
while (Stk.Count > 0) {
JyoutaiDef2 Popped = Stk.Pop();
long CurrNode = Popped.CurrNode;
foreach (EdgeInfoDef EachEdgeInfo in mEdgeInfoListDict[CurrNode]) {
long FromNode = CurrNode;
long ToNode = EachEdgeInfo.ToNode;
long EdgeHash = GetEdgeHash(FromNode, ToNode);
if (UsedEdgeSet.Add(EdgeHash) == false) {
continue;
}
long NewVal = EachEdgeInfo.SumVal - Popped.CurrVal;
if (NewVal < 0) return false;
if (pResultDict.ContainsKey(ToNode)) {
if (pResultDict[ToNode] != NewVal) {
return false;
}
}
pResultDict[ToNode] = NewVal;
WillPush.CurrNode = ToNode;
WillPush.CurrVal = NewVal;
Stk.Push(WillPush);
}
}
return true;
}
struct JyoutaiDef2
{
internal long CurrNode;
internal long CurrVal;
}
// 枝のハッシュ値
static long GetEdgeHash(long pNode1, long pNode2)
{
long MinNode = Math.Min(pNode1, pNode2);
long MaxNode = Math.Max(pNode1, pNode2);
return MaxNode * 1000000 + MinNode;
}
}