旧的几篇题解

一些高中时候的奇怪题解

Freda的城堡

来源: codevs 2490/bzoj3035/gxyz.openjudge.cn11867

思路

将每个入侵者与每个防御塔分别抽象成两个点集{invaders},{defences}
将每个防御塔每次射击与其能够达到的入侵者连边,这样我们就得到了一幅二分图

  • ”每次射击”:

拿一个防御塔来说,它每t时会发射一次,总共有T时,那么它可以发射floor(T/t)次,也就是说它可以消灭这么多次个敌人。将每次发射抽象为一个点,连边,如:若有N个防御塔,第i个防御塔第n次发射抽象出的点为(i*n+N)。

问题转化为:
第$i$次发射记为$d_i$,第$i$个入侵者记为$t_i$,找到集合大小$|{d}|$的最小值。此时${d}$与${t}$最接近二分图的完美匹配

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
#include <cmath>
#include <cstring>
#include <iomanip>
#include <iostream>
#include <queue>
using namespace std;

#define INF 0x7fff
#define SIZE 1000000

int launchers, invaders;
double launchT, cooldownT;
double Distance[300][300];
int head[SIZE], Next[SIZE], tot = 1, Start, End;
struct edge {
int dest, Time;
} graph_list[SIZE];
void push_front(int from, int to, int weight) {
graph_list[++tot].dest = to;
graph_list[tot].Time = weight;
Next[tot] = head[from];
head[from] = tot;
}
void connect(int from, int to, int d) {
push_front(from, to, d);
push_front(to, from, 0);
}

queue<int> bfsCore;
int depth[SIZE];
bool bfs() {
memset(depth, 0, sizeof(depth));
while (bfsCore.size())
bfsCore.pop();
depth[Start] = 1;
bfsCore.push(Start);
while (bfsCore.size()) {
int current = bfsCore.front();
bfsCore.pop();
for (int i = head[current]; i; i = Next[i]) {
int dest = graph_list[i].dest;
if (!depth[dest] && graph_list[i].Time)
depth[dest] = depth[current] + 1,
bfsCore.push(dest);
}
}
if (depth[End])
return true;
return false;
}
int dfs(int current, int CurrentTime) {
if (current == End || CurrentTime == 0)
return CurrentTime;
int remaining = CurrentTime;
for (int i = head[current]; i; i = Next[i]) {
int v = graph_list[i].dest;
if (depth[v] == depth[current] + 1 && graph_list[i].Time) {
int timeRemaining = dfs(v, min(remaining, graph_list[i].Time));
if (timeRemaining > 0) {
remaining -= timeRemaining;
graph_list[i].Time -= timeRemaining;
graph_list[i ^ 1].Time += timeRemaining;
if (!remaining)
break;
} else
depth[v] = 0;
}
}
if (CurrentTime - remaining == 0)
depth[current] = 0;
return CurrentTime - remaining;
}
int Can_kill() {
int ans = 0;
while (bfs()) {
int tmp = dfs(Start, INF);
if (tmp == 0)
break;
ans += tmp;
}
return ans;
}

bool able_to_success(double givenTime) {
tot = 1;
memset(head, 0, sizeof(head));
memset(Next, 0, sizeof Next);
int d = (givenTime - launchT) / (launchT + cooldownT) + 1;
for (int i = 1; i <= launchers; i++) {
for (int j = 0; j < d; j++) {
double now = launchT + j * (launchT + cooldownT);
for (int k = 1; k <= invaders; k++) {
if (now + Distance[i][k] <= givenTime)
connect(i + j * launchers, d * launchers + k, 1);
}
}
}
Start = 0;
End = d * launchers + invaders + 1;
for (int i = 1; i <= d * launchers; i++)
connect(Start, i, 1);
for (int i = d * launchers + 1; i <= d * launchers + invaders; i++)
connect(i, End, 1);
return Can_kill() == invaders;
}

double MinTime() {
double l = launchT, r = INF;
int maxStep = 50; //20+20

while (l - r != 0 && maxStep--) {
double mid = (l + r) / 2;
if (able_to_success(mid))
r = mid;
else
l = mid;
}
return l;
}

int x[SIZE], y[SIZE];
double dis(int x1, int y1, int x2, int y2) {
double a = x1 - x2, b = y1 - y2;
return sqrt(a * a + b * b);
}
int main() {
double v;
cin >> launchers >> invaders >> launchT >> cooldownT >> v;
launchT /= 60;
for (int i = 1; i <= invaders; i++)
cin >> x[i] >> y[i];
for (int i = 1; i <= launchers; i++) {
int destX, destY;
cin >> destX >> destY;
for (int j = 1; j <= invaders; j++)
Distance[i][j] = dis(x[j], y[j], destX, destY) / v;
}
cout << fixed << setprecision(6) << MinTime();
return 0;
}

互不侵犯

来源: SCOI2005/luoguP1896

压位dp

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
#include <iostream>
using namespace std;
long long mem[5000][15][105];
typedef unsigned long long status;
int n, max_status, step_limit;
int count(status &a) {
int ans = 0;
for (int i = 0; i < n; i++)
ans += ((a >> i) & 1);
return ans;
}
int dfs(status last, int remain, int step = 1) {
if (remain < 0 || remain > ((n >> 1) + (n % 2)) * (((n - step + 1) >> 1) + ((n - step + 1) % 2)))
return 0;
if (step > n)
return !remain;
if (mem[last][step][remain])
return mem[last][step][remain];
long long ans = 0;
for (status now = 0; now <= max_status; now++) {
if ((now & (now << 1)) || (now & last) || (now & (last << 1)) || (now & (last >> 1)))
continue;
ans += dfs(now, remain - count(now), step + 1);
}
return mem[last][step][remain] = ans;
}
int main() {
cin >> n >> step_limit;
max_status = ~-(1 << n);
cout << dfs(0ll, step_limit);
}

华容道

来源: luoguP1979/NOIP2013

首先我们可以通过人生经验得知这是一道图论题,但是我们发现需要抽象点。
我们发现棋面每一步移动都可以导向另一个棋面,于是我们可以把每一步移动当作一个点。
对于每一个点,有四个移动方式(上下左右)(↑↑↓↓←→←→ABAB)将每个移动编号,跑SPFA

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
#include<iostream>
#include<vector>
#include<list>
#include<queue>
#include<cstring>
using namespace std;
#define SIZE 31
bool map[SIZE][SIZE];
int SizeX, SizeY;
int EmptyX, EmptyY;
int StartX, StartY;
int TargX, TargY;
int gamePlays;
struct Graph {
static const int MAXNODE = 10000;
struct Edge {
int dest, weight;
Edge(int d, int w) :
dest(d), weight(w) {}
};
list<Edge>map[MAXNODE];
};
struct SPFA :private Graph {
int dis[MAXNODE];
bool visited[MAXNODE];
queue<int>joblist;
void clear() {
memset(dis, 1, sizeof dis);
memset(visited, 0, sizeof visited);
while (!joblist.empty())joblist.pop();
}
void work() {
while (!joblist.empty()) {
int current = joblist.front();
joblist.pop();
visited[current] = 0;
list<Edge>::iterator i = map[current].begin();
for (; i != map[current].end(); i++) {
if (dis[i->dest] > dis[current] + i->weight) {
dis[i->dest] = dis[current] + i->weight;
if (!visited[i->dest]) {
joblist.push(i->dest);
visited[i->dest] = 1;
}
}
}
}
}
void connect(int a, int b, int w) {
map[a].push_front(Edge(b, w));
}
};

struct point {
int x, y, step;
point(int x, int y, int s) :
x(x), y(y), step(s) {}
};
bool visited[SIZE][SIZE];
int dx[4] = { 1,-1,0,0 };
int dy[4] = { 0,0,1,-1 };
int priceToMoveTo(int StartX, int StartY, int EndX, int EndY, int BlankX, int BlankY) {//bfs
queue<point>joblist;
if (StartX == EndX&&StartY == EndY)return 0;
joblist.push(point(StartX, StartY, 0));
memset(visited, 0, sizeof visited);
visited[StartX][StartY] = 1;
while (!joblist.empty()) {
point current = joblist.front();
joblist.pop();
if (current.x == EndX&¤t.y == EndY)return current.step;
for (int i = 0; i < 4; i++) {
/*ille*/if (visited[current.x + dx[i]][current.y + dy[i]])
continue;
/*fixed*/if (!map[current.x + dx[i]][current.y + dy[i]])
continue;
/*blank*/if (current.x + dx[i] == BlankX && current.y + dy[i] == BlankY)
continue;
visited[current.x + dx[i]][current.y + dy[i]] = 1;
joblist.push(point(current.x + dx[i], current.y + dy[i], current.step + 1));
}
}
return 16843009;
}


int id[SIZE][SIZE][4];
void RenewID() {
int temp = 1;
for (int i = 1; i <= SizeY; i++) {
for (int j = 1; j <= SizeX; j++)
for (int k = 0; k < 4; k++)
if (map[i][j] && map[i + dx[k]][j + dy[k]])
id[i][j][k] = temp++;
}
}
void readMap() {
cin >> SizeY >> SizeX >> gamePlays;
for (int i = 1; i <= SizeY; i++)
for (int j = 1; j <= SizeX; j++)
cin >> map[i][j];
}
int main() {
readMap();
SPFA instG;
RenewID();
for (int i = 1; i <= SizeY; i++)
for (int j = 1; j <= SizeX; j++)
for (int k = 0; k < 4; k++)
if (id[i][j][k])
instG.connect(
id[i][j][k],
id[i + dx[k]][j + dy[k]][k ^ 1],
1);
for (int a = 1; a <= SizeY; a++)
for (int b = 1; b <= SizeX; b++)
for (int i = 0; i < 4; i++)
for (int j = 0; j < 4; j++) {
if (i == j)continue;
if (!id[a][b][i] || !id[a][b][j])continue;
instG.connect(
id[a][b][i],
id[a][b][j],
priceToMoveTo(a + dx[i], b + dy[i], a + dx[j], b + dy[j], a, b)
);
}
while (gamePlays--) {
cin >> EmptyX >> EmptyY >>
StartX >> StartY >>
TargX >> TargY;
/////////////
if (StartX == TargX&&StartY == TargY) {
cout << 0 << endl;
continue;
}
instG.clear();
for (int i = 0; i < 4; i++) {
if (id[StartX][StartY][i]) {
instG.joblist.push(id[StartX][StartY][i]);
instG.visited[id[StartX][StartY][i]] = 1;
instG.dis[id[StartX][StartY][i]] =
priceToMoveTo(EmptyX, EmptyY, StartX + dx[i], StartY + dy[i], StartX, StartY);
}
}
instG.work();
/////////////
int Min = 16843009;
for (int i = 0; i < 4; i++) {
if (id[TargX][TargY][i] && instG.dis[id[TargX][TargY][i]] < Min)
Min = instG.dis[id[TargX][TargY][i]];
}
cout << (Min == 16843009 ? -1 : Min) << endl;
////////////
}
}

找啊找啊找GF

来源: luoguP1509

写过的最有意思的题解233333

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
#define 我开始审视这个妹子,心中想到 how_sad = false;
#define 那真是个悲伤的故事 how_sad = true;
#define 拿下这个妹子就多个妹子陪 (dp[j][k] < dp[j - money_cost[i]][k - rp_cost[i]] + 1)
#define 这个妹子比前面那个省事 (dp[j][k] == dp[j - money_cost[i]][k - rp_cost[i]] \
&& time[j][k] > time[j - money_cost[i]][k - rp_cost[i]] + time_cost[i])
#define 如果 if
#define 而且 &&
#define 或者 ||
#define 我 (
#define 的话 )
#define 没钱没人品 j < money_cost[i] || k < rp_cost[i]
#define 有钱而且有人品 (!how_sad)
#define 那我就 ){
#define 推倒她 dp[j][k] = dp[j - money_cost[i]][k - rp_cost[i]] + 1; \
time[j][k] = time[j - money_cost[i]][k - rp_cost[i]] + time_cost[i];
#define 的说 }
#define 如果推倒她并没有什么用 else
#define 那我管她呢 dp[j][k] = dp[j][k], time[j][k] = time[j][k];

#include<iostream>
using namespace std;
#define MAX_GIRLS 101
int money_cost[MAX_GIRLS], rp_cost[MAX_GIRLS], time_cost[MAX_GIRLS];
int my_money, my_rp;
int dp[MAX_GIRLS][MAX_GIRLS],
time[MAX_GIRLS][MAX_GIRLS];

int main() {
int girls; cin >> girls;
for (int i = 1; i <= girls; i++)
cin
>> money_cost[i]
>> rp_cost[i]
>> time_cost[i];
cin >> my_money >> my_rp;
bool how_sad;
for (int i = 1; i <= girls; i++)
for (int j = my_money; j>0; j--)
for (int k = my_rp; k > 0; k--) {
我开始审视这个妹子,心中想到
如果 我 没钱没人品 的话
那真是个悲伤的故事
如果 我 有钱而且有人品 而且 我
拿下这个妹子就多个妹子陪
或者 这个妹子比前面那个省事 的话
那我就 推倒她 的说
如果推倒她并没有什么用
那我管她呢
}
cout << time[my_money][my_rp];
}

拯救公主

来源: http://noi.openjudge.cn/ch0205/7221/

带状态的bfs,变量命名鬼才

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
#include <iostream>
#include <cstring>
#include <queue>
#include<cmath>
#define Never 0x7ffff
using namespace std;
int princeLocX, princeLocY;
int princessLocX, princessLocY;
struct point {
int x, y;
int kindsOfGemsCollected, timePassed;
point(int x, int y, int Info, int time) {
this->x = x;
this->y = y;
this->kindsOfGemsCollected = Info;
timePassed = time;
}
};
struct portalsMadeByThoughtfulMe {
int x, y;
}portalList[15];

int sizeY, sizeX, kindsOfGemsTOCollect;
int dirX[4] = { 1, -1, 0, 0 };
int dirY[4] = { 0, 0, 1, -1 };
int TimeToSavePrincess = 0;
char map[210][210];
bool visited[210][210][32];

bool allGemsAreCollected(int CollectedGemInfo) {
int cntCollected = 0;
for (int i = 0; i <= 4; i++) {
if ((CollectedGemInfo >> i) & 1)
cntCollected++;
}
return (cntCollected >= kindsOfGemsTOCollect);
}
bool reachable(int x, int y, int GemInfo) {
if (x >= 0 && x < sizeY && y >= 0 && y < sizeX && map[x][y] != '#' && visited[x][y][GemInfo] == false)return true;
else return false;
}
void bfs(int startX, int startY, const int targetX, const int targetY, int cntPortal) {
queue<point> bfsCore;
bfsCore.push(point(startX, startY, 0, 0));
while (!bfsCore.empty()) {
point currentLoc = bfsCore.front();
bfsCore.pop();
if (currentLoc.x == targetX && currentLoc.y == targetY && allGemsAreCollected(currentLoc.kindsOfGemsCollected)) {
TimeToSavePrincess = currentLoc.timePassed;
return;
}
if (map[currentLoc.x][currentLoc.y] == '.') {
for (int i = 0; i < 4; i++) {
int nextX = currentLoc.x + dirX[i];
int nextY = currentLoc.y + dirY[i];
if (reachable(nextX, nextY, currentLoc.kindsOfGemsCollected)) {
visited[nextX][nextY][currentLoc.kindsOfGemsCollected] = true;
bfsCore.push(point(nextX, nextY, currentLoc.kindsOfGemsCollected, currentLoc.timePassed + 1));
}
}
}
if (map[currentLoc.x][currentLoc.y] >= '0' && map[currentLoc.x][currentLoc.y] <= '4') {
int newGemInfo = currentLoc.kindsOfGemsCollected | (1 << (map[currentLoc.x][currentLoc.y] - '0'));
for (int i = 0; i < 4; i++) {
int nextX = currentLoc.x + dirX[i];
int nextY = currentLoc.y + dirY[i];
if (reachable(nextX, nextY, newGemInfo)) {
visited[nextX][nextY][newGemInfo] = true;
bfsCore.push(point(nextX, nextY, newGemInfo, currentLoc.timePassed + 1));
}
}
}
if (map[currentLoc.x][currentLoc.y] == '$') {
for (int i = 0; i < cntPortal; i++) {
for (int j = 0; j < 4; j++) {
int nextX = portalList[i].x + dirX[j];
int nextY = portalList[i].y + dirY[j];
if (nextX >= 0 && nextX < sizeY && nextY >= 0 && nextY < sizeX && map[nextX][nextY] != '#' && visited[nextX][nextY][currentLoc.kindsOfGemsCollected] == false) {
visited[nextX][nextY][currentLoc.kindsOfGemsCollected] = true;
bfsCore.push(point(nextX, nextY, currentLoc.kindsOfGemsCollected, currentLoc.timePassed + 1));
}
}
}
}
}
TimeToSavePrincess = Never;
}

int main() {
int cases;
cin >> cases;
while (cases--) {
memset(visited, 0, sizeof(visited));
//attention::
//there's difference between prince and princess!!!!
//prince is man and princess is woman!!!!

int cnt = 0;
cin >> sizeY >> sizeX >> kindsOfGemsTOCollect;
for (int i = 0; i < sizeY; i++) {
for (int j = 0; j < sizeX; j++) {
cin >> map[i][j];
switch (map[i][j]) {
case '$':
portalList[cnt].x = i;
portalList[cnt].y = j;
cnt++;
break;
case 'S':
princeLocX = i;
princeLocY = j;
map[i][j] = '.';
break;
case 'E':
princessLocX = i;
princessLocY = j;
map[i][j] = '.';
break;
}
}
}
bfs(princeLocX, princeLocY, princessLocX, princessLocY, cnt);
if (TimeToSavePrincess != Never)
cout << TimeToSavePrincess << endl;
else cout << "oop!\n";
}
}

旅游

来源: luoguP2610/ZJOI2012

由于这样的图一定有:连了两条边的点有且仅有两个,这两个点之间的路径能够通过所有的城市
所以就是要找到任意一个连了两条边的点
对于任意的点,最短路径最长的那个节点总是如上所述的点。
所以对任意节点SPFA,然后找到$max(dis[i])$,再从这里重新SPFA,$output(max(dis[i]))$

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
#include<vector>
#include<algorithm>
#include<cstring>
#include<queue>
#include<cstdio>
using namespace std;
int nextInt() {
int ret = 0; char buf = getchar();
while (!isdigit(buf))buf = getchar();
while (isdigit(buf)) {
ret *= 10;
ret += buf - '0';
buf = getchar();
}
return ret;
}
void putInt(int x) {
static char buf[10], cnt;
cnt = 0;
while (x)buf[cnt++] = x % 10, x /= 10;
while (cnt--)putchar(buf[cnt] + '0');
}
struct Graph {
vector<int>map[200001];
void connect(int a, int b) {
map[a].push_back(b);
map[b].push_back(a);
}
};
struct SPFA :Graph {
int dis[200001]; bool inQueue[200001];
void work(int x) {
memset(inQueue, 0, sizeof inQueue);
memset(dis, -1, sizeof dis);
queue<int>joblist;
joblist.push(x); dis[x] = 0;
inQueue[x] = 1;
while (joblist.size()) {
int current = joblist.front(); joblist.pop();
for (int i = 0; i < map[current].size(); i++) {
if (dis[map[current][i]] < 1 + dis[current]) {
dis[map[current][i]] = dis[current] + 1;
if (!inQueue[map[current][i]]) {
joblist.push(map[current][i]);
inQueue[map[current][i]] = 1;
}
}
}
}
}

}G;
struct CityEdge {
int a, b, city_id;
friend bool operator <(const CityEdge &a, const CityEdge &b) {
if (a.b == b.b)return a.a < b.a;
else return a.b < b.b;
}
};
vector<CityEdge>temp;
int main() {
int n = nextInt();
for (int i = 1; i < n - 1; i++) {
int a = nextInt(), b = nextInt(), c = nextInt();
if (a > b)swap(a, b);
if (a > c)swap(a, c);
if (b > c)swap(b, c);
temp.push_back({ a,b,i });
temp.push_back({ a,c,i });
temp.push_back({ b,c,i });
}
sort(temp.begin(), temp.end());
for (int i = 0; i < temp.size() - 1; i++) {
if (temp[i].a == temp[i + 1].a&&temp[i].b == temp[i + 1].b)
G.connect(temp[i].city_id, temp[i + 1].city_id);
}
int should_from, max_dis = 0;
G.work(1);
for (int i = 1; i < n - 1; i++) {
if (G.dis[i] > max_dis)max_dis = G.dis[i], should_from = i;
}
G.work(should_from);
for (int i = 1; i < n - 1; i++)if (G.dis[i] > max_dis)max_dis = G.dis[i];
putInt(max_dis+1);
return 0;
}

灾难

来源: BZOJ2815/ZJOI2012

一个物种灭绝当且仅当这个物种的所有食物的lca灭绝

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
#include<iostream>
#include<vector>
#include<queue>
#include<cstring>
#define memset(x,y) memset(x,y,sizeof x)
using namespace std;
int n;
#define maxn 70000
class Graph {
vector<int>map[maxn];
int inDegree[maxn];
public:
vector<int>topoOrder;
Graph() {
memset(inDegree, 0);
}
vector<int> &operator [](int pos) {
return map[pos];
}
void connect(int from, int to) {
map[from].push_back(to);
inDegree[to]++;
}
void topoSort() {
queue<int>joblist;
for (int i = 1; i <= n; i++)
if (!inDegree[i])joblist.push(i);
while (!joblist.empty()) {
int current = joblist.front(); joblist.pop();
topoOrder.push_back(current);
for (int i = 0; i < map[current].size(); i++) {
inDegree[map[current][i]]--;
if (!inDegree[map[current][i]])
joblist.push(map[current][i]);
}
}
}
}G;
class DistinctTree {
int depth[maxn], father[maxn][17];
vector<int>map[maxn];
int lca(int x, int y) {
if (x == -1)return y;
if (depth[x] < depth[y])swap(x, y);
int delta = depth[x] - depth[y];
for (int i = 0; i < 17 && delta; i++) {
if (delta&(1 << i)) {
x = father[x][i];
delta ^= 1 << i;
}
}
for (int i = 16; i >= 0; i--) {
if (father[x][i] != father[y][i])
x = father[x][i], y = father[y][i];
}
return (x == y ? x : father[x][0]);
}
public:
DistinctTree() {
memset(depth, 0); memset(father, 0);
}
vector<int> &operator[](int pos) {
return map[pos];
}
void build(vector<int>&topo) {
depth[0] = 1;//super node
for (int i = topo.size() - 1; i >= 0; i--) {
int current = topo[i];
int current_father = -1;
for (int i = 0; i < G[current].size(); i++)
current_father = lca(current_father, G[current][i]);
if (current_father == -1)current_father = 0;
map[current_father].push_back(current);
depth[current] = depth[current_father] + 1;
father[current][0] = current_father;
for (int i = 0; i < 16 && father[current][i]; i++)
father[current][i + 1] = father[father[current][i]][i];
}
#undef current
}
}DT;
int FINAL[maxn];
int FINAL_DFS(int current) {
int cnt = 1;
for (int i = 0; i < DT[current].size(); i++)
cnt += FINAL_DFS(DT[current][i]);
return FINAL[current] = cnt;
}
int main() {
cin >> n; int other;
for (int i = 1; i <= n; i++) {
cin >> other;
while (other) {
G.connect(i, other);
cin >> other;
}
}
G.topoSort();
DT.build(G.topoOrder);
FINAL_DFS(0);
for (int i = 1; i <= n; i++)
cout << FINAL[i] - 1 << endl;
}