Submission #257267

#TimeUsernameProblemLanguageResultExecution timeMemory
257267maximath_1Graph (BOI20_graph)C++11
100 / 100
449 ms45576 KiB
/*
	* BOI 2020 2A: Graph
	* Set a variable x on one vertex
	* Express values of all vertices in terms of x
	* If there is colliding information, no solution
	* Else, take the minimum of the sum
	* Ah also do that for every connected component :|
*/
//I have started to include headers one by one
//Because I need to wait like a minute for it to compile in my pc
#include <stdio.h>
#include <assert.h>
#include <time.h>
#include <math.h>
#include <algorithm>
#include <vector>
#include <queue>
#include <map>
#include <unordered_map>
#include <set>
#include <unordered_set>
#include <bitset>
#include <deque>
#include <iostream>
#include <limits>
#include <string>
#include <tuple>
#include <iterator>
#include <complex>
#include <random>
#include <iomanip>
using namespace std;
 
#define ll long long
#define ld long double
const ll inf = 1e18;
const ld eps = 1e-6;
struct eq{
	ld m, c; //mx + c
	eq(){}
	eq(ld a, ld b) : m(a) , c(b) {}
 
	eq& operator+=(const eq&rhs){m += rhs.m, c += rhs.c; return *this;}
	eq& operator-=(const eq&rhs){m -= rhs.m, c -= rhs.c; return *this;}
	friend eq operator+(eq a, const eq& b) {return a += b;}
	friend eq operator-(eq a, const eq& b) {return a -= b;}
};
 
ld solv(eq a, eq b){
	//a.m x + a.c = b.m x + b.c
	if(abs(a.m - b.m) < eps){
		if(abs(a.c - b.c) > eps) return -(ld)inf; //no solution
		else return (ld)inf; //inf many solution
	}
	return (ld)(b.c - a.c) / (ld)(a.m - b.m); //one solution
}
ld f(eq a, ld x){
	return (ld)a.m * x + (ld)a.c;
}
 
int n, m;
eq nod[100005];
ld x; //var
vector<pair<int, int> > adj[100005];
bitset<100005> vis;
vector<int> cc;
ld ans[100005];
bool x_found = false, fail_condition = false;
 
void dfs(int nw, int bf, eq cr){
	if(fail_condition) return; //pretty much self explanatory
	if(vis[nw]){
		//compare the existing equation with the new one
		ld get = solv(nod[nw], cr);
		if(abs(get) < eps) get = 0.0; //you know those -0.0? yea to deal with that
		if(abs(get + inf) < eps) fail_condition = true; //no sol
		else if(abs(get - (ld)inf) > eps){
			if(x_found && abs(x - get) > eps) fail_condition = true; //conflicting x val
			else{
				x = get; x_found = true; //x found
			}
		}
		return;
	}
 
	cc.push_back(nw);
	nod[nw] = cr; vis[nw] = 1;
	for(pair<int, int> nx : adj[nw]) if(nx.first != bf){
		eq nex(0, nx.second);
		nex -= nod[nw];
		dfs(nx.first, nw, nex);
	}
	return;
}
 
unordered_map<ll, int> viss;
ll hash_(int a, int b){
	return a * 200005ll + b;
}
 
int main(){
	ios_base::sync_with_stdio(0); cin.tie(0); cout.tie(0);
	cout << fixed << setprecision(10);
 
	//read
	cin >> n >> m;
	for(int u, v, w, i = 0; i < m; i ++){
		cin >> u >> v >> w;
		if(viss[hash_(u, v)]){
			if(viss[hash_(u, v)] == w) continue;
			cout << "NO\n";
			return 0;
		}
		viss[hash_(u, v)] = viss[hash_(v, u)] = w;
		adj[u].push_back({v, w});
		if(u != v) adj[v].push_back({u, w});
	}
 
	//solve
	vis = 0;
	for(int i = 1; i <= n; i ++) if(!vis[i]){
		cc.clear(); x_found = false;
		dfs(i, i, eq(1, 0));
		if(fail_condition) break;
		if(!x_found){
			//check annoying self-loops >:V
			bool flag = false;
			for(int j : cc){
				if(viss[hash_(j, j)]){
					x = solv(nod[j], eq(0, (ld)viss[hash_(j, j)] / 2.0));
					flag = true; break;
				}
			}
			if(!flag){
				//This point, you can do slope trick, ternary search or whatever
				//Easiest is to take the median of the values
				vector<ld> values;
				for(int j : cc) values.push_back(solv(nod[j], eq(0, 0)));
				sort(values.begin(), values.end());
				if(values.size() % 2 == 0)
					x = values[values.size() / 2] + values[values.size() / 2 - 1];
				else
					x = values[values.size() / 2] + values[values.size() / 2];
				x /= (ld)2.0;
			}
		}
		for(int j : cc) ans[j] = f(nod[j], x);
	}
 
	for(int i = 1; i <= n; i ++){
		for(pair<int, int> j : adj[i]){
			if(abs((ld)ans[i] + (ld)ans[j.first] - (ld)j.second) > eps){
				printf("NO\n"); return 0;
			}
		}
	}
 
	//print
	if(fail_condition) cout << "NO\n";
	else{
		cout << "YES\n";
		for(int i = 1; i <= n; i ++)
			cout << ans[i] << " ";
	}
	return 0;
}
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...