BZOJ2117 [2010国家集训队]Crash的旅游计划

本文版权归ljh2000和博客园共有,欢迎转载,但须保留此声明,并给出原文链接,谢谢合作。

 

 

本文作者:ljh2000
作者博客:http://www.cnblogs.com/ljh2000-jump/
转载请注明出处,侵权必究,保留最终解释权!

 

题目链接:BZOJ2117

正解:动态树分治

解题报告:

  考虑维护一棵动态树分治的结构树,因为是树高严格$log$的,所以就可以暴力往上跳了。

  先建出这棵树,然后维护树分治结构中的所有点到分治重心的距离,以及到分治重心的分治结构父亲的距离。

  对于每个点,二分答案,然后计算与他距离$<=mid$的点的个数,往上跳的时候加加减减,容斥一下计算答案。

  注意动态树分治的结构与原树大不相同!计算贡献、距离什么的都要仔细考虑!

 

//It is made by ljh2000
//有志者,事竟成,破釜沉舟,百二秦关终属楚;苦心人,天不负,卧薪尝胆,三千越甲可吞吴。
#include <algorithm>
#include <iostream>
#include <cstring>
#include <vector>
#include <cstdio>
#include <string>
#include <queue>
#include <cmath>
#include <ctime>
#define lc root<<1
#define rc root<<1|1
#define rep(i,j,k) for(int i=j;i<=k;i++)
#define reg(i,x) for(int i=first[x];i;i=next[i])
using namespace std;
typedef long long LL;
const int MAXN = 200011;
const int MAXM = 400011;
int n,k,ecnt,first[MAXN],to[MAXM],next[MAXM],w[MAXM],S,minl,size[MAXN],tot,father[MAXN],dis[MAXN],dis2[MAXN];
bool vis[MAXN];
vector<int>D1[MAXN],D2[MAXN];
inline void link(int x,int y,int z){ next[++ecnt]=first[x]; first[x]=ecnt; to[ecnt]=y; w[ecnt]=z; }
inline int getint(){
    int w=0,q=0; char c=getchar(); while((c<'0'||c>'9') && c!='-') c=getchar();
    if(c=='-') q=1,c=getchar(); while (c>='0'&&c<='9') w=w*10+c-'0',c=getchar(); return q?-w:w;
}

namespace jump{
	int f[MAXN][20],deep[MAXN],g[MAXN][20];
	inline void dfs(int x,int fa){ reg(i,x) { int v=to[i]; if(v==fa) continue; deep[v]=deep[x]+1; g[v][0]=w[i]; f[v][0]=x; dfs(v,x); } }
	inline void Init(){ deep[1]=1; dfs(1,0); for(int j=1;j<=19;j++) for(int i=1;i<=n;i++) f[i][j]=f[f[i][j-1]][j-1],g[i][j]=g[i][j-1]+g[f[i][j-1]][j-1];}
	inline int getdis(int x,int y){
		if(x==y) return 0; if(deep[x]<deep[y]) swap(x,y);//!!!
		int tot=0,t=0; while((1<<t)<=deep[x]) t++; t--;
		for(int i=t;i>=0;i--) if(deep[x]-(1<<i)>=deep[y]) tot+=g[x][i],x=f[x][i]; if(x==y) return tot;
		for(int i=t;i>=0;i--) if(f[x][i]!=f[y][i]) tot+=g[x][i],tot+=g[y][i],x=f[x][i],y=f[y][i]; 
		tot+=g[x][0]; tot+=g[y][0];
		return tot;
	}
}

inline void calcw(int x,int fa){
	size[x]=1; tot++;
	for(int i=first[x];i;i=next[i]){
		int v=to[i]; if(v==fa || vis[v]) continue;
		calcw(v,x); size[x]+=size[v];
	}
}

inline void dp(int x,int fa){
	int maxs=0;
	for(int i=first[x];i;i=next[i]){
		int v=to[i]; if(v==fa || vis[v]) continue;
		dp(v,x); maxs=max(maxs,size[v]);
	}
	maxs=max(maxs,tot-size[x]);
	if(maxs<minl) minl=maxs,S=x;
}

inline void getrt(int &x){
	tot=0; calcw(x,0); 
	S=0; minl=n+1;
	dp(x,0); x=S;
}

inline void dfs(int x,int fa,int nowrt,int lei){
	D2[nowrt].push_back(dis[x]); dis2[x]=dis[x];
	dis[x]=lei; D1[nowrt].push_back(lei);
	for(int i=first[x];i;i=next[i]) {
		int v=to[i]; if(v==fa || vis[v]) continue;
		dfs(v,x,nowrt,lei+w[i]);
	}
}

inline int solve(int x){
	getrt(x); vis[x]=1;
	dfs(x,0,x,0);
	if(tot==1) return x;
	for(int i=first[x];i;i=next[i]) {
		int v=to[i]; if(vis[v]) continue;
		father[solve(v)]=x;//!!!
	}
	return x;
}

inline bool calc(int x,int val){
	int tot=0,savval=val,savx=x,last=0;
	while(x) {
		val=savval-jump::getdis(x,savx);
		//if(val<0) return false;//!!!

		if(last) { tot-=upper_bound(D2[last].begin(),D2[last].end(),val)-D2[last].begin(); }

		tot+=upper_bound(D1[x].begin(),D1[x].end(),val)-D1[x].begin();
		if(tot>k) return true;

		/*if(father[x]) {
			//printf("---%d\n",upper_bound(D2[x].begin(),D2[x].end(),val)-D2[x].begin());
			tot-=upper_bound(D2[x].begin(),D2[x].end(),val)-D2[x].begin();
		}*/
		last=x;
		x=father[x];
	}
	return false;
}

inline void getans(int x){
	int l=0,r=(1<<30)-1,mid;
	int ans=0;
	while(l<=r) {
		mid=(l+r)>>1;
		if(calc(x,mid)) r=mid-1,ans=mid;
		else l=mid+1;
	}
	printf("%d\n",ans);
}

inline void work(){
	n=getint(); k=getint(); int x,y,z;
	for(int i=1;i<n;i++) { x=getint(); y=getint(); z=getint(); link(x,y,z); link(y,x,z); }
	jump::Init();
	solve(1);
	for(int i=1;i<=n;i++) sort(D1[i].begin(),D1[i].end()),sort(D2[i].begin(),D2[i].end());
	for(int i=1;i<=n;i++) 
		getans(i);
}

int main()
{
#ifndef ONLINE_JUDGE
	freopen("2117.in","r",stdin);
	freopen("2117.out","w",stdout);
#endif
    work();
    return 0;
}
//有志者,事竟成,破釜沉舟,百二秦关终属楚;苦心人,天不负,卧薪尝胆,三千越甲可吞吴。

  

posted @ 2017-04-14 10:44  ljh_2000  阅读(224)  评论(0编辑  收藏  举报