牛客挑战赛49

先咕咕咕着……
https://ac.nowcoder.com/acm/contest/11189#description

https://ac.nowcoder.com/discuss/642482?type=101&channel=-1&source_id=0

打到一半电脑爆了(学校电脑把我的U盘系统烧坏了/大哭)
然后就开始摸鱼了
后面看了看题目质量好像还可以
简单写一下题解

C alan的DP题

一个log的做法是很容易想到的,启发式合并,线段树合并,可并堆……
但是这题要线性才能过
分析一下上面那几个做法的共性,都是考虑对每个点及其子树来搞的,不太容易优化成线性

可以换一个思维考虑每个点对祖先的,用并查集维护断点
相当于按照 c [ i ] c[i] c[i]把树剖分成了若干条链,然后考虑每个点,倒着做,找到链顶,然后对于链顶的那个要求就选当前点,然后再把这条链并到上一条上面
具体看代码吧:
code:


#include<bits/stdc++.h>
#define N 3000050
using namespace std;
int fa[N], p[N], size[N], n, m;
int get(int x) {
	return (fa[x] == x)? x : (fa[x] = get(fa[x]));
}
int main() {
	scanf("%d%d", &n, &m);
	for(int i = 1; i <= n; i ++) scanf("%d", &p[i]), fa[i] = p[i];
	for(int i = 1, x = 0; i <= m; i ++) scanf("%d", &x), size[x] ++, fa[x] = x; 
	
	long long ans = 0;
	for(int i = n; i >= 1; i --) {
		int x = get(i);
		if(size[x]) {
			ans += i; size[x] --;
			if(!size[x]) fa[x] = p[x];
		}
	} printf("%lld", ans);
	return 0;
}

posted @ 2021-04-17 09:09  lahlah  阅读(21)  评论(0编辑  收藏  举报