BalticOI 2022 D2T2 Stranded Far From Home 题解

First Post:

Last Update:

被部分分误导了。/fn

也要考虑比赛时碰到这种情况怎么办,”回撤“思路的能力要提升,不能拘泥于当前想的方向中。

正解思路比较直接。

考虑从一个点开始拓展时,记 ,然后把包含 的一个连通块拓展了,然后将 置为该连通块的点权和,然后继续拓展下去。

容易发现拓展两次之后 的值就会翻倍。所以这样的拓展只有 次。

每次拓展时,我们需要查询包含 的,点权 的一个连通块的信息。使用 kruskal 重构树 + 倍增即可。单次查询是 的。

所以本题就做完了,时间复杂度 。(其中 为值域)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
#include <bits/stdc++.h>
using namespace std;
#define FI first
#define SE second
#define mkp make_pair
const int N = 4e5 + 5,Lg = 20;
typedef long long ll;
int n,m,s[N];
vector<int> G[N];
struct Edge {
int u,v,w;
Edge(){}
bool operator < (const Edge &rhs) const { return w < rhs.w;}
} e[N];
int val[N],anc[Lg][N];
ll wsze[N];
int ufs[N];
int find(int x) { return ufs[x] == x ? x : ufs[x] = find(ufs[x]);}
int main() {
cin >> n >> m;
for(int i = 1;i <= n;i++) cin >> s[i],wsze[i] = s[i];
for(int i = 1;i <= m;i++)
cin >> e[i].u >> e[i].v,e[i].w = max(s[e[i].u],s[e[i].v]);
sort(e + 1,e + m + 1);
for(int i = 1;i <= n + n;i++) ufs[i] = i;
int tot = n;
for(int i = 1;i <= m;i++)
if(find(e[i].u) != find(e[i].v)) {
int p = ++tot,lc = find(e[i].u),rc = find(e[i].v);
val[p] = e[i].w;ufs[lc] = ufs[rc] = p;
anc[0][lc] = anc[0][rc] = p;wsze[p] = wsze[lc] + wsze[rc];
}
for(int j = 1;j < Lg;j++)
for(int i = 1;i <= tot;i++) anc[j][i] = anc[j - 1][anc[j - 1][i]];
for(int i = 1;i <= n;i++) {
ll now = s[i];
int x = i;
while(true) {
for(int j = Lg - 1;j >= 0;j--)
if(anc[j][x] && val[anc[j][x]] <= now) x = anc[j][x];
if(wsze[x] == now) break;
now = wsze[x];
}
if(!anc[0][x]) putchar('1');
else putchar('0');
}
return 0;
}