AtCoder Beginner Contest 218

https://atcoder.jp/contests/abc218

F - Blocked Roads

题意

给定一张 nn 个点 mm 条边的有向图。对于 i=1,2,,mi=1,2,\cdots,m,求删除第 ii 条边后 11nn 的最短路。

数据范围:2n400,1mn×(n1)2\leq n\leq400,1\leq m\leq n\times(n-1)

题解

直接做bfs求最短路是 O(n+m)O(n+m) 的,对于 mm 条边每条都做显然不行。而 11nn 的最短路上至多有 n1n-1 条边。只需要对这些边重新跑bfs,其它边一定不会影响最短路的长度。

G - Game on Tree 2

题意

给定一棵 nn 个点的树。两个人从根节点出发轮流移动,每次走向一个未访问过的相邻的点。最终求出所有访问过的点的点权的中位数,先手希望最大化,后手希望最小化。求双方最优策略下的结果。

数据范围:1n1051\leq n\leq 10^5

题解

容易发现最终一定走向一个叶子结点。那么我们可以处理出每个叶子结点到根的路径上所有点的中位数,然后直接dp。记 fif_i 为走到 ii 的答案,走向子结点中最大或最小的那个就可以了。中位数可以使用对顶堆维护。

代码

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
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
#include <bits/stdc++.h>
using namespace std;
multiset<int> S,T;
void eval()
{
if(S.size())
{
auto it=S.end();it--;
T.insert(*it);S.erase(it);
}
while(S.size()<T.size())
{
S.insert(*T.begin());T.erase(T.begin());
}
}
int val()
{
auto it=S.end();it--;
if(S.size()==T.size()+1) return *it;
return (*it+*T.begin())/2;
}
void insert(int x)
{
S.insert(x);
eval();
}
void erase(int x)
{
auto it=S.end();it--;
if(*it<x) T.erase(T.lower_bound(x));
else S.erase(S.lower_bound(x));
eval();
}
const int N=1e5+5;
int a[N],f[N];
vector<int> g[N];
void dfs(int u,int fa,int d)
{
insert(a[u]);
int mn=0x3f3f3f3f,mx=0;
for(auto v:g[u])
if(v!=fa)
{
dfs(v,u,d+1);
mn=min(mn,f[v]),mx=max(mx,f[v]);
}
if(mx==0) f[u]=val();
else if(d&1) f[u]=mn;
else f[u]=mx;
erase(a[u]);
}
int main()
{
ios::sync_with_stdio(false);
cin.tie(nullptr);
int n;cin>>n;
for(int i=1;i<=n;i++) cin>>a[i];
for(int i=1;i<n;i++)
{
int u,v;cin>>u>>v;
g[u].push_back(v),g[v].push_back(u);
}
dfs(1,0,0);
cout<<f[1]<<'\n';
return 0;
}

AtCoder Beginner Contest 218
https://je3ter.github.io/2023/11/21/ACM/AtCoder Beginner Contest 218/
作者
Je3ter
发布于
2023年11月21日
许可协议