Codeforces 501C:Misha and Forest(好题+思维+异或的运算规律+树)

11 篇文章 0 订阅
1 篇文章 0 订阅
C. Misha and Forest
time limit per test
1 second
memory limit per test
256 megabytes
input
standard input
output
standard output

Let's define a forest as a non-directed acyclic graph (also without loops and parallel edges). One day Misha played with the forest consisting of n vertices. For each vertex v from 0 to n - 1 he wrote down two integers, degreev and sv, were the first integer is the number of vertices adjacent to vertex v, and the second integer is the XOR sum of the numbers of vertices adjacent to v (if there were no adjacent vertices, he wrote down 0).

Next day Misha couldn't remember what graph he initially had. Misha has values degreev and sv left, though. Help him find the number of edges and the edges of the initial graph. It is guaranteed that there exists a forest that corresponds to the numbers written by Misha.

Input

The first line contains integer n (1 ≤ n ≤ 216), the number of vertices in the graph.

The i-th of the next lines contains numbers degreei and si (0 ≤ degreei ≤ n - 10 ≤ si < 216), separated by a space.

Output

In the first line print number m, the number of edges of the graph.

Next print m lines, each containing two distinct numbers, a and b (0 ≤ a ≤ n - 10 ≤ b ≤ n - 1), corresponding to edge (a, b).

Edges can be printed in any order; vertices of the edge can also be printed in any order.

Examples
input
3
2 3
1 0
1 0
output
2
1 0
2 0
input
2
1 1
1 0
output
1
0 1
Note

The XOR sum of numbers is the result of bitwise adding numbers modulo 2. This operation exists in many modern programming languages. For example, in languages C++, Java and Python it is represented as "^", and in Pascal — as "xor".


题目大意:给你一个数字n,代表n个节点,编号为0~n-1,接下来n行,分别对应每个节点的信息,每行两个数字,第一个数字是与该点连接的点的个数,第二个数字是与该点连接的所有点的异或结果,让你求出该图的边的条数和每条边的两端编号。(注:题中说明该图是无向无环图,就是一棵树

解题思路:

这是一个无向无环图,也就是一棵树,那么它就肯定有叶子结点,叶子节点的度数为1,此时它相邻点的异或结果实际上就是所求点的编号了。然后把跟叶子节点相邻的点的度数减去1,代表把叶子节点去除,此时异或结果是有变的。需要用本来的异或结果跟该叶子节点再异或一次,就得出除了这个叶子节点外其他点的异或值了,即a^b^c^a=b^c。


代码如下:

#include <cstdio>
#include <queue> 
using namespace std;
int in[70000];//存每个点连接的点的个数 
int orsum[70000];//存每个点的异或结果 
int main()
{
	int n;
	scanf("%d",&n);
	queue<int>que;
	pair<int,int>bian[70000];//申请一个存边的数组 
	for(int i=0;i<n;i++)
	{
		scanf("%d%d",&in[i],&orsum[i]);
		if(in[i]==1)//如果某个点连接的点的个数是1,那么说明它是最下面一层的点,把该点放到队列里面 
		{
			que.push(i);
		}
	}
	int cnt=0;//统计边的个数 
	while(!que.empty())
	{
		int from=que.front();
		que.pop();
		if(in[from]==1)//这个判断,不能少,因为 第一个例子中0的度数在该过程中会变成0 
		{
			int to=orsum[from];
			bian[cnt].first=from;
			bian[cnt].second=to;
			cnt++;
			in[from]--;
			in[to]--;
			orsum[to]=orsum[to]^from;//更新异或结果 
			if(in[to]==1)
			{
				que.push(to);
			}
		}
	}
	printf("%d\n",cnt);
	for(int i=0;i<cnt;i++)
	{
		printf("%d %d\n",bian[i].first,bian[i].second);
	}
	return 0;
} 


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值