【笔记】P6419 [COCI2014-2015#1] Kamp 答辩做法
模拟赛 T3,用非常答辩的做法过掉了。5k 代码写完后竟只调了10分钟
首先考虑指定出发点如何算答案。
用一眼看出法,就是把出发点也定为必经点后,\(必经点连通距离\times 2\ -\ 出发点到某一必经点的最大距离\)。这个想法可以由 P9304 的思路得到。再有,要求树上所有点的答案,多半是换根。
然后就考虑怎么对所有点求答案。
首先要维护换起点时算必经点连通距离,也就是说要支持加必经点和删必经点,可以想到 AcWing355。其关键推论是:将所有必经点按照时间戳排序成一圈,答案就是相邻两个节点之间的路径长度值和。然后写个 LCA,再搞个 set 瞎维护一下就好。
其次考虑如何维护出发点到某一必经点的最大距离。考虑把根从 \(x\) 换到 \(y\),那么在 \(y\) 子树内的必经点深度要全部 \(-dis\)(x,y间边权),而子树外必经点深度就全部 \(+dis\)。所以我们只要把必经点抠出来排成一个序列,整一个线段树维护区间 \(\max\) 和区间加就好了。\(y\) 子树对应的区间边界可以二分。
然后这个题就做完了。复杂度应该是大常数的 \(O(nlogn)\)。
//If, one day, I finally manage to make my dreams a reality...
//I wonder, will you still be there by my side?
#include<bits/stdc++.h>
#define IOS ios::sync_with_stdio(false)
#define TIE cin.tie(0),cout.tie(0)
#define int long long
#define y1 cyy
#define fi first
#define se second
#define cnt1(x) __builtin_popcount(x)
#define mk make_pair
#define pb push_back
#define pii pair<int,int>
#define ls(x) (x<<1)
#define rs(x) (x<<1|1)
#define lbt(x) (x&(-x))
#define inf 0x3f3f3f3f
using namespace std;
int n,m,k[500005],dfn[500005],dis[500005],timer,u,v,w;
int dep[500005],fa[500005][20],F[500005],siz[500005];
bool fl[500005];
struct node{
int to,dis;
};
vector<node> a[500005];
bool cmp(int x,int y){
return dfn[x]<dfn[y];
}
void dfs0(int x,int f){
dfn[x]=++timer,dep[x]=dep[f]+1;
siz[x]=1;
fa[x][0]=f;
for(int i=1;i<=19;i++) fa[x][i]=fa[fa[x][i-1]][i-1];
for(auto tmp:a[x]){
if(tmp.to==f) continue;
dis[tmp.to]=dis[x]+tmp.dis;
dfs0(tmp.to,x);
siz[x]+=siz[tmp.to];
}
}
int Lca(int u,int v){
if(dep[u]<dep[v]) swap(u,v);
for(int i=19;i>=0;--i){
if(dep[fa[u][i]]>=dep[v]) u=fa[u][i];
}
if(u==v) return u;
for(int i=19;i>=0;--i){
if(fa[u][i]!=fa[v][i]) u=fa[u][i],v=fa[v][i];
}
return fa[u][0];
}
int Dis(int u,int v){
return dis[u]+dis[v]-dis[Lca(u,v)]*2;
}
set<pii> s;
int ans1;
void Insert(int x){
if(s.size()==2){
s.insert({dfn[x],x});
return ;
}
auto now=s.insert({dfn[x],x}).first;
auto Pre=prev(now),Nex=next(now);
if(Pre==s.begin()) Pre=--(s.find({inf,inf}));
if(Nex==(--s.end())) Nex=(++(s.begin()));
pii u=*Pre,v=*Nex;
ans1-=Dis(u.second,v.second);
ans1+=Dis(u.second,x)+Dis(x,v.second);
}
void Delete(int x){
if(s.size()==3){
s.erase(s.find({dfn[x],x}));
return ;
}
auto now=s.find({dfn[x],x});
auto Pre=prev(now),Nex=next(now);
if(Pre==s.begin()) Pre=--(s.find({inf,inf}));
if(Nex==(--s.end())) Nex=(++(s.begin()));
pii u=*Pre,v=*Nex;
ans1+=Dis(u.second,v.second);
ans1-=Dis(u.second,x)+Dis(x,v.second);
s.erase(now);
}
struct SGT{
struct node{
int l,r,mx,tag;
}tr[2000005];
void build(int i,int l,int r){
tr[i].l=l,tr[i].r=r,tr[i].tag=0;
if(l==r){
tr[i].mx=dis[k[l]];
return ;
}
int mid=(l+r)>>1;
build(ls(i),l,mid),build(rs(i),mid+1,r);
tr[i].mx=max(tr[ls(i)].mx,tr[rs(i)].mx);
}
void pushdown(int i){
if(tr[i].tag){
tr[ls(i)].tag+=tr[i].tag;
tr[rs(i)].tag+=tr[i].tag;
tr[ls(i)].mx+=tr[i].tag;
tr[rs(i)].mx+=tr[i].tag;
tr[i].tag=0;
}
}
void add(int i,int l,int r,int k){
if(tr[i].l>=l&&tr[i].r<=r){
tr[i].tag+=k,tr[i].mx+=k;
return ;
}
pushdown(i);
int mid=(tr[i].l+tr[i].r)>>1;
if(l<=mid) add(ls(i),l,r,k);
if(mid<r) add(rs(i),l,r,k);
tr[i].mx=max(tr[ls(i)].mx,tr[rs(i)].mx);
}
int query(int i,int l,int r){
if(tr[i].l>=l&&tr[i].r<=r) return tr[i].mx;
pushdown(i);
int mid=(tr[i].l+tr[i].r)>>1,ans=0;
if(l<=mid) ans=max(ans,query(ls(i),l,r));
if(mid<r) ans=max(ans,query(rs(i),l,r));
return ans;
}
}sgt;
int getl(int x){
int l=1,r=m,ans=m;
while(l<=r){
int mid=(l+r)>>1;
if(dfn[k[mid]]>=x) ans=mid,r=mid-1;
else l=mid+1;
}
return ans;
}
int getr(int x){
int l=1,r=m,ans=1;
while(l<=r){
int mid=(l+r)>>1;
if(dfn[k[mid]]<=x) ans=mid,l=mid+1;
else r=mid-1;
}
return ans;
}
void dfs1(int x,int f,int dd){
int L=getl(dfn[x]),R=getr(dfn[x]+siz[x]-1);
if(x!=1){
if(!fl[x]) Insert(x);
// cout<<x<<":"<<endl;
// cout<<L<<' '<<R<<' '<<dd<<endl;
sgt.add(1,1,m,dd);
sgt.add(1,L,R,-dd*2);
// for(int i=1;i<=m;i++) cout<<sgt.query(1,i,i)<<' ';
// cout<<endl;
F[x]=ans1;
F[x]-=sgt.query(1,1,m);
// cout<<ans1<<' '<<sgt.query(1,1,m)<<endl;
if(!fl[x]) Delete(x);
}
for(auto tmp:a[x]){
if(tmp.to==f) continue;
dfs1(tmp.to,x,tmp.dis);
}
if(x!=1){
sgt.add(1,1,m,-dd);
sgt.add(1,L,R,dd*2);
}
}
signed main(){
IOS;TIE;
cin>>n>>m;
for(int i=1;i<n;i++){
cin>>u>>v>>w;
a[u].pb({v,w}),a[v].pb({u,w});
}
dfs0(1,0);
for(int i=1;i<=m;i++) cin>>k[i];
sort(k+1,k+m+1,cmp);
sgt.build(1,1,m);
s.insert({-1,-1}),s.insert({inf,inf});
for(int i=1;i<=m;i++) Insert(k[i]),fl[k[i]]=1;
if(!fl[1]) Insert(1);
F[1]=ans1-sgt.query(1,1,m);
if(!fl[1]) Delete(1);
dfs1(1,0,0);
for(int i=1;i<=n;i++) cout<<F[i]<<'\n';
return 0;
}