[Luogu4149][IOI2011]Race

BZOJ权限题qwq
Luogu

sol

树上路径当然是淀粉质辣!
考虑所有过重心的路径。开一个\(10^6\)大小的数组\(t\)表示某一路径长度的最小边数,初始化为\(inf(i>0)\)\(t[0]=0\)
枚举重心的每棵子树进行\(dfs\),假设获得了一条从重心出发边数为\(dep\)边权和为\(dis\)的路径,就可以用\(t[K-dis]+dep\)更新答案。
更新完答案后对应用\(dep\)更新\(t[dis]\)
记得还原\(t\)数组。显然不能直接memset设为\(inf\)。只需把更改过的位置改成\(inf\)即可。

code

#include<cstdio>
#include<algorithm>
using namespace std;
int gi()
{
    int x=0,w=1;char ch=getchar();
    while ((ch<'0'||ch>'9')&&ch!='-') ch=getchar();
    if (ch=='-') w=0,ch=getchar();
    while (ch>='0'&&ch<='9') x=(x<<3)+(x<<1)+ch-'0',ch=getchar();
    return w?x:-x;
}
const int inf = 1e9;
const int N = 2e5+5;
int n,k,to[N<<1],nxt[N<<1],len[N<<1],head[N],cnt;
int sz[N],w[N],root,sum,vis[N],t[N*5],ans=inf;
void link(int u,int v,int ww)
{
	to[++cnt]=v;nxt[cnt]=head[u];len[cnt]=ww;
	head[u]=cnt;
}
void getroot(int u,int f)
{
	sz[u]=1;w[u]=0;
	for (int e=head[u];e;e=nxt[e])
	{
		int v=to[e];if (v==f||vis[v]) continue;
		getroot(v,u);
		sz[u]+=sz[v];w[u]=max(w[u],sz[v]);
	}
	w[u]=max(w[u],sum-sz[u]);
	if (w[u]<w[root]) root=u;
}
void getans(int u,int f,int dep,int dis)
{
	if (dis>k) return;
	ans=min(ans,t[k-dis]+dep);
	for (int e=head[u];e;e=nxt[e])
	{
		int v=to[e];if (v==f||vis[v]) continue;
		getans(v,u,dep+1,dis+len[e]);
	}
}
void getdp(int u,int f,int dep,int dis)
{
	if (dis>k) return;
	t[dis]=min(t[dis],dep);
	for (int e=head[u];e;e=nxt[e])
	{
		int v=to[e];if (v==f||vis[v]) continue;
		getdp(v,u,dep+1,dis+len[e]);
	}
}
void clear(int u,int f,int dep,int dis)
{
	if (dis>k) return;
	t[dis]=inf;
	for (int e=head[u];e;e=nxt[e])
	{
		int v=to[e];if (v==f||vis[v]) continue;
		clear(v,u,dep+1,dis+len[e]);
	}
}
void solve(int u)
{
	vis[u]=1;
	for (int e=head[u];e;e=nxt[e])
		if (!vis[to[e]])
			getans(to[e],u,1,len[e]),getdp(to[e],u,1,len[e]);
	for (int e=head[u];e;e=nxt[e])
		if (!vis[to[e]])
			clear(to[e],u,1,len[e]);
	for (int e=head[u];e;e=nxt[e])
	{
		int v=to[e];if (vis[v]) continue;
		sum=sz[v];root=0;
		getroot(v,0);
		solve(root);
	}
}
int main()
{
	n=gi();k=gi();
	for (int i=1,u,v,ww;i<n;++i)
	{
		u=gi()+1;v=gi()+1;ww=gi();
		link(u,v,ww);link(v,u,ww);
	}
	for (int i=1;i<=k;++i) t[i]=inf;
	sum=w[0]=n;
	getroot(1,0);
	solve(root);
	printf("%d\n",ans==inf?-1:ans);
	return 0;
}
posted @ 2018-02-23 19:39  租酥雨  阅读(202)  评论(0编辑  收藏  举报