题目描述
有N个人,编号为1至N,他们相互之间拜师学艺。
某个时刻,如果甲向乙拜师,一般情况下乙就将甲收为徒弟。这时乙会将甲视为大徒弟,而所有甲的徒弟(如果有的话)便成为乙的小徒弟。
但是,每个人都不想收太多的大徒弟。如果乙当前大徒弟数量超过他的期望值,他便会拒绝甲,而让甲拜自己的某一位大徒弟为师。甲总是想选好的师傅,而如果一个人的所有徒弟数量很多,往往说明他水平比较高,所以甲会选乙的徒弟中,拥有最多徒弟的人。如果有不止一个人徒弟最多,甲会选择最早向乙拜师的那位。于是接下来,就是新的一次拜师过程,甲向乙的某位徒弟拜师。甲直到拜师成功才会停止。
每个人每一时刻最多只会有一个师傅。有师傅的人若再向其他人拜师,就会先断绝与当前师傅的师徒关系。若甲不认乙为师,乙也就不认甲为大徒弟,同时甲和他的徒弟们也因此与甲的师傅脱离关系(当然包括师傅的师傅,师傅的师傅的师傅……)。
两个人之间的师徒关系可能是变化的。所以若甲向乙多次拜师,则甲向乙拜师的时间将以最后一次拜师的时间算。
一开始,每个人都没有师傅,也没有徒弟。我们事先告诉你每个人愿意收的最多大徒弟数量,达到了这个数量,他就不再收大徒弟,除非又有某个大徒弟与他断绝了关系。接下来每一时刻,就有人相互拜师,而所有拜师都会按照上面的规则进行。此外,一个人也不会向自己当前的任何一位徒弟拜师。
请你统计,所有拜师过程结束后,每个人有多少大徒弟,小徒弟。
输入
第一行给出两个整数N和M(5<=N<=10000,0<=M<=10000),其中N表示总人数,M表示有多少组拜师的人。
第二行,包含N个正整数,依次表示每个人愿意收的最多大徒弟的数量。
接下来M行,每行两个整数A和B,按时间顺序依次表示一对拜师的人。总是A向B拜师。
输出
输出包括N行,每行有两个整数,之间用一个空格隔开。第i行的两个数分别表示,在所有拜师结束后,编号为i的人拥有的大徒弟数量和小徒弟数量。
样例输入
6 7
2 2 2 2 2 2
2 1
3 1
4 1
5 1
6 1
6 3
3 2
样例输出
1 4
2 2
1 0
1 1
0 0
0 0
题意非常的绕:而且要注意比如甲拜师乙,甲的徒弟仍然时甲的徒弟,不过此时他的徒弟也变成了乙的徒孙,也就是小徒弟。
如果能够正确理解这一点就行了,分析可知,我们只需要维护大徒弟是谁就行了。
代码如下:
#include<iostream>
#include<cstring>
#include<cstdio>
#include<string>
#include<cmath>
#include<vector>
#include<algorithm>
#include<set>
#include<map>
#include<queue>
using namespace std;
const int MAX = 10010;
struct Node {
set<int> Big;
int father;
int time;
int MaxSize;
bool CanVisit() {
if (Big.size() < MaxSize)
return true;
else
return false;
}
Node() {
Big.clear();
father = -1;
time = -1;
MaxSize = -1;
}
};
int N, M;
Node ac[MAX];
//获得这个跟人的所有徒弟数量。
int Getpupil(int v) {
int res = (int)ac[v].Big.size();
for (set<int>::iterator it = ac[v].Big.begin(); it != ac[v].Big.end(); ++it) {
res += Getpupil(*it);
}
return res;
}
void VisitScholar(int u,int v,int time) {
if (ac[v].CanVisit()) {
int f = ac[u].father;
if (f != -1) {//如果之前有师傅,就从师傅哪里删除
ac[f].Big.erase(u);
}
ac[u].father = v;
ac[u].time = time;
ac[v].Big.insert(u);
}
else {
int pos = -1;
int Max = 0;
for (set<int>::iterator it = ac[v].Big.begin(); it != ac[v].Big.end(); ++it) {
int sum = Getpupil(*it);
if (pos == -1 || sum > Max) {
pos = *it;
Max = sum;
}
else if (sum == Max && ac[*it].time < ac[pos].time) {
pos = *it;
Max = sum;
}
}
//寻找符合拜师的开始再次拜师,直到拜师成功为止。
VisitScholar(u, pos, time);
}
}
int main(void) {
scanf("%d%d", &N, &M);
for (int i = 1; i <= N; ++i) {
scanf("%d", &ac[i].MaxSize);
}
int u, v;
for (int i = 1; i <= M; ++i) {
scanf("%d%d", &u, &v);
VisitScholar(u, v, i);
}
for (int i = 1; i <= N; ++i) {
printf("%d ", (int)ac[i].Big.size());
int sum = 0;
//统计所有小徒弟
for (set<int>::iterator it = ac[i].Big.begin(); it != ac[i].Big.end(); ++it) {
sum += Getpupil(*it);
}
printf("%d\n", sum);
}
return 0;
}