ARC115F Migration
有一棵 \(n\) 个节点的树,编号为 \(i\) 的点权值为 \(h_i\)。
你有 \(k\) 个棋子,第 \(i\) 个棋子初始在编号为 \(s_i\) 的点上。你需要进行若干次移动,每次移动可以将一个棋子移到相邻的点上。特别的,多个棋子可以在同一个点上。你需要将第 \(i\) 个棋子移动到编号为 \(t_i\) 的点上。
设第 \(i\) 个棋子在编号为 \(p_i\) 的点上,我们定义当前状态的势能为 \(\sum\limits_{i=1}^{k} h_{p_i}\)。你需要最小化移动过程中势能的最大值。
\(1 \leq n,k \leq 2000\),\(1 \leq h_i \leq 10^9\)。
草,学习了一下午发现理解错了。
我们不妨先定义一种严格的偏序关系:若 \(p_u < p_v\) 或 \(p_u = p_v\) 且 \(u < v\),则称 \(u\) 优于 \(v\)。
记 \(dis(u,v)\) 为 \(u\) 到 \(v\) 路径上的最大权值。对于每个点 \(u\),我们考虑对于所有优于 \(u\) 的点 \(v\),求出使得 \(dis(u,v)\) 最小的 \(v\),若有多个取最优的 \(v\)。记 \(f_u=v\),且记 \(w_u=dis(u,v)\)。我们容易在 \(O(n^2)\) 的时间复杂度内求出所有的 \(f_u\) 和 \(w_u\)。
我们考虑对于初始状态 \(S\) 和目标状态 \(T\) 进行移动,我们希望每次移动后的势能减少。则每次移动选择某个状态的某个棋子,设其在编号为 \(u\) 的点上,则将其移动到 \(f_u\) 上。假设当前状态的势能为 \(X\),则过程中会产生的最大势能为 \(X-h_u+w_u\),移动后的势能为 \(X-h_u+h_{f_u}\)。我们对于所有不相同的 \(s_i\) 和 \(t_i\) 加入堆,按照 \(w_u-h_u\) 的顺序操作即可。
细节见代码,复杂度 \(O(nk \log k)\)。
谁家模拟赛把这个放 T2。
#include<iostream>
#include<cstdio>
#include<vector>
#include<queue>
#include<algorithm>
using namespace std;
const long long INF=0x3f3f3f3f3f3f3f3f;
vector<int> G[2010];
long long h[2010],w[2010];
int f[2010];
bool better(int lhs,int rhs){
return h[lhs]<h[rhs] || h[lhs]==h[rhs] && lhs<rhs;
}
void dfs(int u,int fa,int root,long long pre_max){
if(better(u,root)){
if(pre_max<w[root] || pre_max==w[root] && better(u,f[root])){
w[root]=pre_max;
f[root]=u;
}
}
for(int i=0;i<G[u].size();i++){
int v=G[u][i];
if(v!=fa){
dfs(v,u,root,max(pre_max,h[v]));
}
}
}
struct Node{
int id;
long long add_val;
};
bool operator <(const Node &lhs,const Node &rhs){
return lhs.add_val>rhs.add_val;
}
priority_queue<Node> q1,q2;
long long ans,ans1,ans2;
int s[2010],t[2010],res;
void move1(){
Node pre=q1.top();
q1.pop();
int id=pre.id;
long long add_val=pre.add_val;
res-=(s[id]!=t[id]);
ans=max(ans,ans1+add_val);
ans1-=h[s[id]];
ans1+=h[f[s[id]]];
s[id]=f[s[id]];
res+=(s[id]!=t[id]);
if(f[s[id]]){
q1.push((Node){id,w[s[id]]-h[s[id]]});
}
}
void move2(){
Node pre=q2.top();
q2.pop();
int id=pre.id;
long long add_val=pre.add_val;
res-=(s[id]!=t[id]);
ans=max(ans,ans2+add_val);
ans2-=h[t[id]];
ans2+=h[f[t[id]]];
t[id]=f[t[id]];
res+=(s[id]!=t[id]);
if(f[t[id]]){
q2.push((Node){id,w[t[id]]-h[t[id]]});
}
}
int main(){
int n;
scanf("%d",&n);
for(int i=1;i<=n;i++){
scanf("%lld",&h[i]);
}
for(int i=1;i<n;i++){
int u,v;
scanf("%d %d",&u,&v);
G[u].push_back(v);
G[v].push_back(u);
}
for(int i=1;i<=n;i++){
w[i]=INF;
dfs(i,-1,i,h[i]);
}
int k;
scanf("%d",&k);
for(int i=1;i<=k;i++){
scanf("%d %d",&s[i],&t[i]);
ans1+=h[s[i]];
ans2+=h[t[i]];
res+=(s[i]!=t[i]);
q1.push((Node){i,w[s[i]]-h[s[i]]});
q2.push((Node){i,w[t[i]]-h[t[i]]});
}
ans=max(ans1,ans2);
while(res){
if(q1.empty()){
move2();
}
else if(q2.empty()){
move1();
}
else{
Node pre1=q1.top(),pre2=q2.top();
if(ans1+pre1.add_val<=ans2+pre2.add_val){
move1();
}
else{
move2();
}
}
}
printf("%lld\n",ans);
return 0;
}

浙公网安备 33010602011771号