C. Misha and Forest
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.
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 - 1, 0 ≤ si < 216), separated by a space.
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 - 1, 0 ≤ 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.
3
2 3
1 0
1 0
2
1 0
2 0
2
1 1
1 0
1
0 1
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个节点,编号为0~n-1,现在对于每一个节点,给出degi,sumi
degi表示节点i的度(入度+出度)
sumi表示所有和节点i直接相连的节点的编号的xor和
输出边的数量和所有边的2个端点
(e=(u,v),则输出u v)
思路:
突破口:当节点i为叶子节点时,只有一个入度,没有出度,则degi=1,这个时候fa[i]=sumi
这个时候和fa[i]相连的边确定了1条了,则:
deg[fa[i]]--
sum[fa[i]]=change(i,sum[fa[i]])
函数change(int b,int c)的功能:
有方程式x^b=c,现在我们知道了b,c,这个函数的返回值是x
那么当deg[fa[i]]==1的时候,就说明节点fa[i]还剩下1条边没有确定,而这条边的另一个顶点就是此时的sum[fa[i]]
则fa[fa[i]]=sum[fa[i]]
对于每一个节点,degi=0时说明没有边与之相连,不用管它
degi>0,就总会有degi=1的时候,这个时候,节点i的父亲节点就确定了
但是这样有一个问题:
对于根节点root是没有父亲节点的,但是会有deg[root]==1的时刻,按照上面的想法这个时候我们给了root一个父亲节点,而实际上, 我们不应该给root这个父亲节点
所以:对于节点i,满足2个条件,才可以确定父亲节点
1.deg[i]==1
2.fa[i.sum]==-1(为了防止给root父亲节点)
#include<cstdio>
#include<cstring>
#include<queue> using namespace std; const int maxn=(<<)+; int fa[maxn];
struct Node
{
int deg,sum,cnt;
};
Node node[maxn]; inline int change(int b,int c)
{
int ret=;
int i=;
while(b>||c>)
{
if((b&)!=(c&))
{
ret+=(<<i);
}
b>>=;
c>>=;
i++;
}
return ret;
} void solve(int ); int main()
{
int n;
scanf("%d",&n);
int tmp=;
for(int i=;i<n;i++)
{
scanf("%d %d",&node[i].deg,&node[i].sum);
tmp+=node[i].deg;
node[i].cnt=i;
}
printf("%d\n",tmp/);
solve(n); return ;
} void solve(int n)
{
memset(fa,-,sizeof fa);
queue<Node>que;
while(!que.empty())
que.pop();
for(int i=;i<n;i++)
{
if(node[i].deg==)
que.push(node[i]);
}
while(!que.empty())
{
Node u=que.front();
que.pop();
if(fa[u.sum]<)
fa[u.cnt]=u.sum;
int j=fa[u.cnt];
node[j].deg--;
node[j].sum=change(u.cnt,node[j].sum);
if(node[j].deg==)
que.push(node[j]);
}
for(int i=;i<n;i++)
{
if(fa[i]!=-)
{
printf("%d %d\n",i,fa[i]);
}
}
return ;
}