[ZJOI2012]灾难

嘟嘟嘟


偶尔翻到的一道题。


50分暴力很好想,对于每一个点进行一次拓扑排序,然后每一次别memset,只清空走过的点,能拿到70分。


正解好像也挺好想,是一个叫“灭绝树”的东西。
对于一个点\(i\),他能否被饿死由他的所有食物决定,而他的所有食物能否被饿死有这些食物的lca决定。所以这时候把lca和\(i\)连边,构成的树就叫灭绝树。答案就是每一个点的子树大小-1。
具体步骤就是先进行拓扑排序,如果一个点入度为0,那么就更新他的深度和倍增数组,并在灭绝树上连边,同时放入队尾。
然后本人因为序号重复的问题调了半天,这多半是废了。

#include<cstdio>
#include<iostream>
#include<cmath>
#include<algorithm>
#include<cstring>
#include<cstdlib>
#include<cctype>
#include<vector>
#include<stack>
#include<queue>
using namespace std;
#define enter puts("") 
#define space putchar(' ')
#define Mem(a, x) memset(a, x, sizeof(a))
#define In inline
typedef long long ll;
typedef double db;
const int INF = 0x3f3f3f3f;
const db eps = 1e-8;
const int maxn = 7e4 + 5;
const int maxe = 4e6 + 5;
inline ll read()
{
	ll ans = 0;
  	char ch = getchar(), last = ' ';
  	while(!isdigit(ch)) last = ch, ch = getchar();
  	while(isdigit(ch)) ans = (ans << 1) + (ans << 3) + ch - '0', ch = getchar();
  	if(last == '-') ans = -ans;
  	return ans;
}
inline void write(ll x)
{
	if(x < 0) x = -x, putchar('-');
  	if(x >= 10) write(x / 10);
  	putchar(x % 10 + '0');
}

int n, s, du[maxn];
vector<int> eat[maxn];
struct Edge
{
	int nxt, to;
}e[maxe], e2[maxe];
int head[maxn], ecnt = -1, head2[maxn], ecnt2 = -1;
In void addEdge(int x, int y)
{
  	e[++ecnt] = (Edge){head[x], y};
  	head[x] = ecnt;
}
In void addEdge2(int x, int y)
{
  	e2[++ecnt2] = (Edge){head2[x], y};
  	head2[x] = ecnt2;
}

const int N = 16;
int dep[maxn], fa[N + 2][maxn];
In ll lca(int x, int y)
{
	if(dep[x] < dep[y]) swap(x, y);
	for(int i = N; i >= 0; --i)
		if(dep[x] - (1 << i) >= dep[y]) x = fa[i][x];
	if(x == y) return x;
	for(int i = N; i >= 0; --i)
		if(fa[i][x] ^ fa[i][y]) x = fa[i][x], y = fa[i][y];
	return fa[0][x];
}
In void build_Tree()
{
	queue<int> q;
	for(int i = 1; i <= n; ++i) if(!du[i]) addEdge2(0, i), dep[i] = 1, q.push(i);
  	while(!q.empty())
  	{
  		int now = q.front(); q.pop();
  		for(int i = head[now], v; i != -1; i = e[i].nxt)
  		{
  			if(!--du[v = e[i].to])
  			{
  				int Lca = eat[v][0];
  				for(int j = 1, sz = eat[v].size(); j < sz; ++j) Lca = lca(Lca, eat[v][j]);
  				addEdge2(Lca, v);
  				fa[0][v] = Lca; dep[v] = dep[Lca] + 1;
  				for(int j = 1; (1 << j) <= dep[v]; ++j)
	  				fa[j][v] = fa[j - 1][fa[j - 1][v]];
	  			q.push(v);
  			}
  		}
  	}
}

int sum[maxn];
In void dfs(int now)
{
	sum[now] = 1;
	for(int i = head2[now]; i != -1; i = e2[i].nxt)
		dfs(e2[i].to), sum[now] += sum[e2[i].to];
}

int main()
{
	Mem(head, -1); Mem(head2, -1);
  	n = read();
  	for(int i = 1; i <= n; ++i)
    {
    	int x = read(); 
      	while(x) ++du[i], addEdge(x, i), eat[i].push_back(x), x = read();
    }
  	build_Tree(); dfs(0);
  	for(int i = 1; i <= n; ++i) write(sum[i] - 1), enter;
  	return 0;
}
posted @ 2019-02-20 21:18  mrclr  阅读(102)  评论(0编辑  收藏  举报