牛客挑战赛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;
}