题意:
有一个n个点的关系图,u->v有边表示u能吃v。
去掉某个点以后会有一些点没有东西吃,每个点的灾难值定义为如果去掉这个点,会没有东西吃的点的个数。
求每个点的灾难值。
n<=65534
做法:
好妙啊QAQ..
首先这个不是树很难受,如果是一棵树,就可以直接计算子树大小得到答案了。
我们考虑把图化成一棵树。
观察到一个奇妙的性质,一个点u,如果和很多点v1,v2…vn都有边(代表u能吃v1,v2…vn),那么它能吃的东西相当于是v1,v2…vn这些点的共同能吃的东西。
于是你想到了什么!结合一下“树”的知识。
lca啊(雾)!
假如我们反着建边,从上往下考虑,如果发现一个点的父亲有多个,就把这个点连向它所有父亲的lca。一层层往下建就建出了一棵树。
于是在树上dfs一遍就得到答案了。
代码:
/*************************************************************
Problem: bzoj 2815 [ZJOI2012]灾难
User: fengyuan
Language: C++
Result: Accepted
Time: 212 ms
Memory: 17452 kb
Submit_Time: 2018-01-24 19:34:32
*************************************************************/
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<iostream>
#include<cctype>
#include<cstdlib>
#include<cmath>
#include<queue>
using namespace std;
typedef long long ll;
inline ll read() {
char ch = getchar(); ll x = 0; int op = 1;
for(; !isdigit(ch); ch = getchar()) if(ch == '-') op = -1;
for(; isdigit(ch); ch = getchar()) x = x*10+ch-'0';
return x*op;
}
inline void write(ll a) {
if(a < 0) putchar('-'), a = -a;
if(a >= 10) write(a/10); putchar('0'+a%10);
}
const int N = 100000, M = 200010;
int n, cnt, tot;
int head[N], headt[N], f[N][25], depth[N], in[N], q2[N], sz[N], vis[N];
struct edge {
int to, nxt;
edge() {}
edge(int x, int y) { to = x, nxt = y; }
}e[M], t[M];
inline void addedge(int x, int y) { e[++ cnt] = edge(y, head[x]); head[x] = cnt; }
inline void addtree(int x, int y) { t[++ cnt] = edge(y, headt[x]); headt[x] = cnt; }
inline void tp() {
queue<int> q;
for(int i = 1; i <= n; i ++) if(!in[i]) q.push(i);
while(!q.empty()) {
int u = q.front(); q.pop(); q2[++ tot] = u;
for(int i = head[u]; i; i = e[i].nxt) {
int v = e[i].to; in[v] --;
if(!in[v]) q.push(v);
}
}
}
inline int lca(int x, int y) {
if(x == -1) return y;
if(depth[x] < depth[y]) swap(x, y);
int tmp = depth[x] - depth[y];
for(int i = 20; i >= 0; i --) if(tmp>>i&1) x = f[x][i];
if(x == y) return x;
for(int i = 20; i >= 0; i --)
if(f[x][i] != f[y][i]) x = f[x][i], y = f[y][i];
return f[x][0];
}
inline void build() {
for(int i = tot; i >= 1; i --) {
int u = q2[i], fa = -1;
for(int j = head[u]; j; j = e[j].nxt) fa = lca(fa, e[j].to);
if(fa == -1) fa = 0; addtree(fa, u); vis[u] = 1;
depth[u] = depth[fa] + 1;
f[u][0] = fa;
for(int i = 1; 1<<i <= depth[u]; i ++) f[u][i] = f[f[u][i-1]][i-1];
}
}
inline void dfs(int u) {
sz[u] = 1;
for(int i = headt[u]; i; i = t[i].nxt) {
int v = t[i].to; dfs(v);
sz[u] += sz[v];
}
}
int main() {
n = read();
for(int i = 1; i <= n; i ++) {
int x = read();
while(x) { addedge(i, x); in[x] ++; x = read(); }
}
tp(); build(); dfs(0);
for(int i = 1; i <= n; i ++) write(sz[i]-1), puts("");
return 0;
}