【Atcoder - AGC004D】Teleporter

版权声明:本文为博主原创文章……懂吗?要尊重别人的劳动成果呐 https://blog.csdn.net/Tiw_Air_Op1721/article/details/84146538


@Problem Statement@

There are N towns in Snuke Kingdom, conveniently numbered 1 through N. Town 1 is the capital.

Each town in the kingdom has a Teleporter, a facility that instantly transports a person to another place. The destination of the Teleporter of town i is town ai (1≤ai≤N). It is guaranteed that one can get to the capital from any town by using the Teleporters some number of times.

King Snuke loves the integer K. The selfish king wants to change the destination of the Teleporters so that the following holds:

Starting from any town, one will be at the capital after using the Teleporters exactly K times in total.
Find the minimum number of the Teleporters whose destinations need to be changed in order to satisfy the king’s desire.

Constraints
2≤N≤10^5
1≤ai≤N
One can get to the capital from any town by using the Teleporters some number of times.
1≤K≤10^9

Input
The input is given from Standard Input in the following format:
N K
a1 a2 … aN

Output
Print the minimum number of the Teleporters whose destinations need to be changed in order to satisfy King Snuke’s desire.

Sample Input 1
3 1
2 3 1
Sample Output 1
2
Change the destinations of the Teleporters to a=(1,1,1).

Sample Input 2
4 2
1 1 2 2
Sample Output 2
0
There is no need to change the destinations of the Teleporters, since the king’s desire is already satisfied.

Sample Input 3
8 2
4 1 2 3 1 2 3 4
Sample Output 3
3
For example, change the destinations of the Teleporters to a=(1,1,2,1,1,2,2,4).

@Translation@

N 个城市,城市 1 为首都。
每一个城市都有一个传送门,传送门通向 N 个城市中的某一个(可以是它自身)。
保证每一个城市都可以通过传送门到达首都。
现在让你修改最少的传送门的目的地,使得每一个城市经过恰好 K 次传送门后到达首都。求这个最少的数量。

@Solution@

首先可以使用反证法证明最后首都的传送门一定是通向自己。
否则假如它通向 i,则首都走 K 次即 i 走 (K-1) 次恰到达首都。然而 i 走 K 次也恰到达首都,又因 i ≠ 首都,所以不可能。

相当于问题是改最少的边,使得所有点的深度 <= K。
假如要更改结点 i 的传送门目的地,则这个目的地改为首都显然更优一些。
不然它的深度还会大些。

贪心地考虑,我们先考虑深度最大的结点,假如它的深度 > K,则对于它来说,一定会更改它的某一个祖先。显然这个祖先的深度越小,能够使更多的结点变为一定合法的状态,即更优秀。

实现上,假如要更改某一个结点 i 的传送门,则将 i 这棵子树内的所有点打上 tag。已经打过 tag 的直接回到父亲。这样每一个结点最多只会被访问两次,因此时间复杂度为 O(n)。

找某一个结点深度最小的,能使这个结点变合法的祖先,也直接暴力跳父亲即可,不需要倍增法。为什么呢?首先你肯定跳了 K 次,然后这 K 个点就会被打上 tag,就不会被重复访问了。这样均摊算下来也是 O(n) 的。

@Code@

#include<cstdio>
#include<algorithm>
using namespace std;
const int MAXN = 100000;
struct edge{
	int to;
	edge *nxt;
}edges[MAXN + 5], *adj[MAXN + 5], *ecnt = &edges[0];
void addedge(int u, int v) {
	edge *p = (++ecnt);
	p->to = v, p->nxt = adj[u], adj[u] = p;
}
struct node{
	int ind; int dep;
}a[MAXN + 5];
bool operator < (node a, node b) {
	return a.dep < b.dep;
}
int N, K;
int fa[MAXN + 5], vis[MAXN + 5], rev[MAXN + 5];
void dfs(int rt) {
	for(edge *p=adj[rt];p!=NULL;p=p->nxt) {
		a[p->to].dep = a[rt].dep + 1;
		dfs(p->to);
	}
}
void dfs2(int rt) {
	if( vis[rt] ) return ;
	vis[rt] = true;
	for(edge *p=adj[rt];p!=NULL;p=p->nxt)
		dfs2(p->to);
}
int main() {
	int ans = 0;
	scanf("%d%d", &N, &K);
	for(int i=1;i<=N;i++) {
		scanf("%d", &fa[i]);
		if( i != 1 ) addedge(fa[i], i);
		else if( fa[i] != 1 ) ans++;
		a[i].ind = i;
	}
	dfs(1);
	sort(a+1, a+N+1);
	for(int i=N;i>=1;i--) {
		if( a[i].dep <= K ) break;
		if( vis[a[i].ind] ) continue;
		ans++; int x = a[i].ind;
		for(int j=1;j<K;j++)
			x = fa[x];
		dfs2(x);
	}
	printf("%d\n", ans);
}

@End@

就是这样,新的一天里,也请多多关照哦(ノω<。)ノ))☆.。

猜你喜欢

转载自blog.csdn.net/Tiw_Air_Op1721/article/details/84146538
今日推荐