【笔记】P6419 [COCI2014-2015#1] Kamp 答辩做法

发布时间 2023-09-23 17:40:34作者: Binary_1110011

模拟赛 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;
}