概述
题干:
The board has got a painted tree graph, consisting of n nodes. Let us remind you that a non-directed graph is called a tree if it is connected and doesn't contain any cycles.
Each node of the graph is painted black or white in such a manner that there aren't two nodes of the same color, connected by an edge. Each edge contains its value written on it as a non-negative integer.
A bad boy Vasya came up to the board and wrote number sv near each node v — the sum of values of all edges that are incident to this node. Then Vasya removed the edges and their values from the board.
Your task is to restore the original tree by the node colors and numbers sv.
Input
The first line of the input contains a single integer n (2 ≤ n ≤ 105) — the number of nodes in the tree. Next n lines contain pairs of space-separated integers ci, si(0 ≤ ci ≤ 1, 0 ≤ si ≤ 109), where ci stands for the color of the i-th vertex (0 is for white, 1 is for black), and si represents the sum of values of the edges that are incident to the i-th vertex of the tree that is painted on the board.
Output
Print the description of n - 1 edges of the tree graph. Each description is a group of three integers vi, ui, wi (1 ≤ vi, ui ≤ n, vi ≠ ui, 0 ≤ wi ≤ 109), where vi and ui— are the numbers of the nodes that are connected by the i-th edge, and wi is its value. Note that the following condition must fulfill cvi ≠ cui.
It is guaranteed that for any input data there exists at least one graph that meets these data. If there are multiple solutions, print any of them. You are allowed to print the edges in any order. As you print the numbers, separate them with spaces.
Examples
Input
3
1 3
1 2
0 5
Output
3 1 3
3 2 2
Input
6
1 0
0 3
1 8
0 2
0 3
0 0
Output
2 3 3
5 3 3
4 3 2
1 6 0
2 1 0
题目大意:
给你n个点,然后是每个点的颜色(用0或1表示)和 与这个点相邻的边的权值,让你恢复一棵树(输出格式为u,v,w(边权))
解题报告:
首先告诉你一定有解了,那么我们只需要构造出一组解就可以了。(因为说明黑色的点的权值之和 等于 白色的点的权值之和)构造的方法选择贪心,每次选择两个最小的黑白点然后 把权值较小的全都连到权值较大的边上,最后别忘了特判剩下的顶点全为0的情况。。。细节不少啊。
AC代码:
#include<cstdio>
#include<iostream>
#include<algorithm>
#include<queue>
#include<map>
#include<vector>
#include<set>
#include<string>
#include<cmath>
#include<cstring>
#define ll long long
#define pb push_back
#define pm make_pair
#define fi first
#define se second
using namespace std;
const int MAX = 2e5 + 5;
vector<pair<int, int> > a,b;//1==黑 0==白
int main()
{
int n;//cout << (1,0) << endl;
cin>>n;
for(int i=1,col,w; i<=n; i++) {
scanf("%d%d",&col,&w);
if(col) a.pb(pm(w,i));
else b.pb(pm(w,i));
}
sort(a.begin(),a.end());
sort(b.begin(),b.end());
// for(int i = 0; i<a.size(); i++) printf("%d %dn",a[i].fi,a[i].se);
int cnt1=0,cnt2=0;
int up1=a.size();
int up2=b.size();
// int zero1=0,zero2=0;
// while(a[zero1].fi == 0) zero1++;
// while(b[zero2].fi == 0) zero2++;
while(cnt1 < up1 && cnt2 < up2) {
int tmp = min(a[cnt1].fi,b[cnt2].fi);
printf("%d %d %dn",a[cnt1].se,b[cnt2].se,tmp);
a[cnt1].fi -= tmp;
b[cnt2].fi -= tmp;
// if(a[cnt1].fi) cnt2++;
// else if(b[cnt2].fi) cnt1++;
if(a[cnt1].fi == 0 && cnt1 < up1-1) cnt1++;
else if(b[cnt2].fi == 0 && cnt2 < up2-1) cnt2++;
else if(cnt1 < up1-1) cnt1++;
else cnt2++;
}
return 0 ;
}
或者用上面那两行注释的也可以。
这样写是不对的:
while(cnt1 < up1 && cnt2 < up2) {
int tmp = min(a[cnt1].fi,b[cnt2].fi);
printf("%d %d %dn",a[cnt1].se,b[cnt2].se,tmp);
a[cnt1].fi -= tmp;
b[cnt2].fi -= tmp;
// if(a[cnt1].fi) cnt2++;
// else if(b[cnt2].fi) cnt1++;
if(a[cnt1].fi == 0 && cnt1 < up1) cnt1++;
else if(b[cnt2].fi == 0 && cnt2 < up2) cnt2++;
对于这样的样例
6
0 0
1 0
0 0
1 0
0 0
1 0
是过不了的、、所以必须cnt1<up1-1这样,对于其他的情况再另行判断
总结:
好cai啊、、、5555又被虐了
其实为了避免上面那些 繁琐的情况,还可以用优先队列写,最后清空的时候直接暴力清空就可以了。
最后
以上就是大胆小蝴蝶为你收集整理的【CodeForces - 260D】Black and White Tree (思维构造,猜结论,细节,构造一棵树)的全部内容,希望文章能够帮你解决【CodeForces - 260D】Black and White Tree (思维构造,猜结论,细节,构造一棵树)所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复