【CodeForces - 260D】Black and White Tree (思维构造,猜结论,细节,构造一棵树)

246 篇文章 1 订阅
21 篇文章 0 订阅

题干:

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 cisi(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 viuiwi (1 ≤ vi, ui ≤ nvi ≠ 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 %d\n",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 %d\n",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 %d\n",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又被虐了

 其实为了避免上面那些 繁琐的情况,还可以用优先队列写,最后清空的时候直接暴力清空就可以了。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值