模擬賽 T2
鏈接:https://sjzezoj.com/contest/428/problem/2449
代碼借鑒了 aqz 大蛇,考場(chǎng)上想到差不多的東西,只是最后我沒(méi)有想出來(lái)具體怎么對(duì)中間的點(diǎn)進(jìn)行統(tǒng)計(jì),所以打了性質(zhì) A, 拿到了 40 pts。
記錄一下我自己的辦法怎么轉(zhuǎn)化成正解。
還是一樣的建 Kruskal 重構(gòu)樹(shù)。
我們維護(hù)一下每個(gè)節(jié)點(diǎn)子樹(shù)中有沒(méi)有指定地點(diǎn),如果有,那么對(duì)于它的子樹(shù)中的 1 節(jié)點(diǎn),它如果是 lca, 那么這個(gè)無(wú)疑就是最優(yōu)的節(jié)點(diǎn)。
所以我們記錄一下從根到每一個(gè)節(jié)點(diǎn)對(duì)于答案的貢獻(xiàn)是多少,并 dfs 出來(lái)離它最近的,子樹(shù)中有制定地點(diǎn)的節(jié)點(diǎn)。
對(duì)于每個(gè)葉子是 0/1 的詢問(wèn)就找到這個(gè)節(jié)點(diǎn)減去它自身的貢獻(xiàn)。
點(diǎn)擊查看代碼
#include <bits/stdc++.h>
/*愉快抄抄aqz*/
#define int long long
using namespace std;
const int MN=1e6+116;
struct Side{
int u, v, w;
bool operator <(const Side &o)const{
return w<o.w;
}
}side[MN];
int n, k, tot, ans, t[MN];
int lc[MN], rc[MN], val[MN];
int sum1[MN], sum0[MN], val1[MN], val0[MN];
int father[MN], to[MN];
bool vis[MN];
int find(int x){
if(father[x]!=x) father[x]=find(father[x]);
return father[x];
}
void dfs1(int u){
if(!lc[u]&&!rc[u]){
if(t[u]==0) sum0[u]++;
else sum1[u]++;
return;
}else{
dfs1(lc[u]); dfs1(rc[u]);
father[lc[u]]=father[rc[u]]=u;
sum1[u]=sum1[lc[u]]+sum1[rc[u]];
sum0[u]=sum0[lc[u]]+sum0[rc[u]];
vis[u]=(vis[lc[u]]|vis[rc[u]]);
}
}
void dfs2(int u, int top){
val0[u]=val0[u]+sum1[u]*val[u]-sum1[u]*val[father[u]];
val1[u]=val1[u]+sum0[u]*val[u]-sum0[u]*val[father[u]];
top=(vis[u]?u:top);
if(!lc[u]&&!rc[u]){
to[u]=top;
return;
}else{
val0[lc[u]]+=val0[u]; val0[rc[u]]+=val0[u];
val1[lc[u]]+=val1[u]; val1[rc[u]]+=val1[u];
dfs2(lc[u],top); dfs2(rc[u],top);
}
}
int ask1(int u){
if(t[u]!=0) return val1[to[u]];
else return val1[to[u]]-val[to[u]];
}
int ask0(int u){
if(t[u]!=1) return val0[to[u]];
else return val0[to[u]]-val[to[u]];
}
void Read(){
cin>>n>>k; tot=n; for(int i=1; i<=n; ++i) father[i]=i;
for(int i=1; i<=n+n; ++i){
vis[i]=sum1[i]=sum0[i]=val0[i]=val1[i]=0;
to[i]=val[i]=lc[i]=rc[i]=0;
}
for(int i=1; i<=n; ++i) cin>>t[i];
for(int i=1; i<n; ++i){
cin>>side[i].u>>side[i].v>>side[i].w;
}
sort(side+1,side+n);
for(int i=1; i<n; ++i){
++tot; val[tot]=side[i].w; father[tot]=tot;
int u=find(side[i].u), v=find(side[i].v);
lc[tot]=u, rc[tot]=v;
father[u]=father[v]=tot;
}
for(int i=1,x; i<=k; ++i){
cin>>x; vis[x]=true;
}
dfs1(tot); father[tot]=0; dfs2(tot,0);
int ans=0;
for(int i=1; i<=n; ++i) if(t[i]==0) ans+=ask0(i);
cout<<ans<<'\n';
for(int i=1; i<=n; ++i){
if(t[i]==0){
cout<<ans-ask0(i)+ask1(i)<<'\n';
}else{
cout<<ans-ask1(i)+ask0(i)<<'\n';
}
}
}
signed main(){
ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);
int T; cin>>T; while(T--){
Read();
}
return 0;
}

浙公網(wǎng)安備 33010602011771號(hào)