Gym 103860B Shuttle Bus 题解
Gym 103860B Shuttle Bus 题解
知识点
可删堆,对顶堆,换根 DP,长链剖分。
分析
首先我们有 \(O(n^2)\) 的暴力做法:我们以每个点为根,暴力对树进行长链剖分。
具体地,设 \(siz_u = \sum_{v\in S(u)} a_v\),其中 \(S(u)\) 表示以 \(u\) 为根的子树内的节点,那么我们将树剖为数条以 \(\sum siz\) 为权值的链,采取长链剖分的方式,用 DP 可以求出,并将这些权值记在相应的叶节点上。
那么从总权值和中减去最长的 \(k\) 条链即可得到答案;或者求出叶节点数 \(cnt\),取出其中最小的 \(cnt-k\) 条链求和就是答案。
考虑优化,首先发现可以使用类似换根的方式解决问题,每次从一个节点到子节点时(称为下传),只会改变最多两个叶节点的权值,那么可以开一个可删对顶堆来维护前 \(cnt-k\) 小,单次修改复杂度 \(O(\log_2{n})\)。
在从 \(u\) 下传到 \(v\) 时,我们还要考虑维护最长链,那么就要判断 \(u,v\) 所属最长链是否相同,并求出 \(u\) 除去 \(S(v)\) 后的最长链,那么只需对所有与 \(u\) 相连的点都遍历一遍,求最长链和次长链即可,与换根 DP 无异。
代码
代码细节较多。
#define Pli pair<ll,int>
#define PQ(x,y) priority_queue<x,vector<x>,y>
constexpr int N(2e5+10);
bool vis[N],typ[N];
int n,m,rt,cnt;
int a[N],fa[N],bot[N],dep[N],idx[N];
ll sum;
ll ans[N],len[N],siz[N],val[N];
vector<int> g[N];
template<class Type,class cmp=less<Type>>struct DPQ {
ll sum;
PQ(Type,cmp) S,T;
DPQ():sum(0),S(PQ(Type,cmp)()),T(PQ(Type,cmp)()) {}
void update() { while(!S.empty()&&!T.empty()&&S.top()==T.top())S.pop(),T.pop(); }
bool empty() { return S.size()<=T.size(); }
int size() { return S.size()-T.size(); }
void insert(Type x) { update(),sum+=x.Fi,S.push(x); }
void erase(Type x) { T.push(x),sum-=x.Fi,update(); }
Type top() { return update(),S.empty()?Type(-1,-1):S.top(); }
};
DPQ<Pli> LQ;
DPQ<Pli,greater<Pli>> GQ;
void Insert(int u) {
const Pli x(val[u],u);
if(LQ.size()<m)return typ[u]=0,LQ.insert(x);
if(x<LQ.top())return typ[LQ.top().Se]=1,typ[u]=0,GQ.insert(LQ.top()),LQ.erase(LQ.top()),LQ.insert(x);
typ[u]=1,GQ.insert(x);
}
void Erase(int u) {
const Pli x(val[u],u);
!typ[u]?LQ.erase(x):GQ.erase(x);
while(!GQ.empty()&&LQ.size()<m)typ[GQ.top().Se]=0,LQ.insert(GQ.top()),GQ.erase(GQ.top());
}
void dfs(int u) {
dep[u]=dep[fa[u]]+1,len[u]=siz[u]=a[u],bot[u]=u;
for(int v:g[u])if(v^fa[u])fa[v]=u,dfs(v),siz[u]+=siz[v];
for(int v:g[u])if(v!=fa[u]&&len[v]+siz[u]>=len[u])len[u]=len[v]+siz[u],bot[u]=bot[v];
}
void DFS(int u) {
/*DE("Cal");*/
g[u].size()==1u?(Erase(u),ans[u]=LQ.sum-(LQ.size()>=m?LQ.top().Fi:0),Insert(u),0):ans[u]=LQ.sum;
if(g[u].size()==1u)return;
/*DE("Find Bots");*/
const int botu(bot[u]);
int _botu(0);
ll Val(0),_Val(0);
bot[u]=_botu=u,val[u]=0;
for(int v:g[u]) {
if(val[bot[v]]>=Val)_Val=Val,_botu=bot[u],Val=val[bot[v]],bot[u]=bot[v];
else if(val[bot[v]]>=_Val)_Val=val[bot[v]],_botu=bot[v];
}
/*DE("To Sons");*/
for(int v:g[u])if(v^fa[u]) {
/*DE("Update");*/
int bot_u(bot[v]==bot[u]?_botu:bot[u]);
const ll sizv(siz[v]);
Erase(bot[v]),val[bot[v]]-=siz[v],Insert(bot[v]);
Erase(bot_u),val[bot_u]+=sum-siz[v],Insert(bot_u);
siz[u]-=siz[v],siz[v]=sum,swap(bot[u],bot_u);
/*DE("DFS");*/
DFS(v);
/*DE("Backtracking");*/
swap(bot[u],bot_u),siz[v]=sizv,siz[u]+=siz[v];
Erase(bot_u),val[bot_u]-=sum-siz[v],Insert(bot_u);
Erase(bot[v]),val[bot[v]]+=siz[v],Insert(bot[v]);
}
bot[u]=botu;
}
signed main() {
#ifdef Plus_Cat
freopen(Plus_Cat ".in","r",stdin),freopen(Plus_Cat ".out","w",stdout);
#endif
/*DE("Input & Build");*/
cin>>n>>m;
if(n<=2) {
FOR(i,1,n)cout<<"0\n";
return 0;
}
FOR(i,1,n)cin>>a[i],sum+=a[i];
FOR(i,2,n) {
int u,v;
cin>>u>>v,g[u].push_back(v),g[v].push_back(u);
}
/*DE("Init");*/
FOR(i,1,n)g[i].size()>1u?rt=i:++cnt;
if(cnt<=m) {
FOR(i,1,n)cout<<"0\n";
return 0;
}
m=cnt-m,dfs(rt);
FOR(i,1,n)idx[i]=i;
sort(idx+1,idx+n+1,[&](const int a,const int b) {
return len[a]^len[b]?len[a]>len[b]:dep[a]<dep[b];
});
FOR(i,1,n) {
const int &u(idx[i]);
if(vis[u]||u==rt)continue;
val[bot[u]]=len[u];
for(int v(bot[u]); v!=rt&&!vis[v]; v=fa[v])vis[v]=true;
}
FOR(i,1,n)if(g[i].size()==1u)Insert(i);
/*DE("DFS");*/
DFS(rt);
/*DE("Output");*/
FOR(i,1,n)cout<<ans[i]<<'\n';
return 0;
}

浙公网安备 33010602011771号