zoukankan      html  css  js  c++  java
  • 【BZOJ3743】[Coci2015]Kamp 树形DP

    【BZOJ3743】[Coci2015]Kamp

    Description

    一颗树n个点,n-1条边,经过每条边都要花费一定的时间,任意两个点都是联通的。
    有K个人(分布在K个不同的点)要集中到一个点举行聚会。
    聚会结束后需要一辆车从举行聚会的这点出发,把这K个人分别送回去。
    请你回答,对于i=1~n,如果在第i个点举行聚会,司机最少需要多少时间把K个人都送回家。

    Input

    第一行两个数,n,K。
    接下来n-1行,每行三个数,x,y,z表示x到y之间有一条需要花费z时间的边。
    接下来K行,每行一个数,表示K个人的分布。

    Output

    输出n个数,第i行的数表示:如果在第i个点举行聚会,司机需要的最少时间。

    Sample Input

    7 2
    1 2 4
    1 3 1
    2 5 1
    2 4 2
    4 7 3
    4 6 2
    3
    7

    Sample Output

    11
    15
    10
    13
    16
    15
    10

    HINT

    【数据规模】
    K <= N <= 500000
    1 <= x,y <= N, 1 <= z <= 1000000

    题解:我们先高出这k个点的虚树,先考虑出发点u这个点是虚树上的点,且必须返回出发点时答案是什么。显然答案就是这个虚树的所有边的长度之和*2。

    那么如果要返回出发点呢?如果我们再v结束,那么答案就会减去dis(u,v),那么显然dis(u,v)越大越好,所以树形DP求一下每个点到虚树上点的距离最大值即可。

    然后如果u不在虚树上呢?那么它还要先走到虚树上,所以再维护一下每个点到虚树上点的距离最小值即可。

    代码还是很不可读的~

    #include <cstdio>
    #include <cstring>
    #include <iostream>
    using namespace std;
    typedef long long ll;
    const int maxn=500010;
    ll ans;
    int to[maxn<<1],next[maxn<<1],val[maxn<<1],head[maxn],p[maxn],q[maxn],s[maxn],fa[maxn],Q[maxn],st[maxn];
    ll dep[maxn],f[maxn][2],g[maxn],h[maxn][2],k[maxn];
    int n,m,cnt,top,np,mp;
    inline int rd()
    {
    	int ret=0,f=1;	char gc=getchar();
    	while(gc<'0'||gc>'9')	{if(gc=='-')f=-f;	gc=getchar();}
    	while(gc>='0'&&gc<='9')	ret=ret*10+gc-'0',gc=getchar();
    	return ret*f;
    }
    void add(int a,int b,int c)
    {
    	to[cnt]=b,val[cnt]=c,next[cnt]=head[a],head[a]=cnt++;
    }
    void dfs(int x)
    {
    	p[x]=++p[0],Q[p[0]]=x;
    	for(int i=head[x];i!=-1;i=next[i])	if(to[i]!=fa[x])	dep[to[i]]=dep[x]+val[i],fa[to[i]]=x,dfs(to[i]);
    	q[x]=p[0];
    }
    int main()
    {
    	n=rd(),m=rd();
    	int i,a,b,c,x,y;
    	ll d;
    	memset(head,-1,sizeof(head));
    	for(i=1;i<n;i++)	a=rd(),b=rd(),c=rd(),add(a,b,c),add(b,a,c);
    	dfs(1);
    	np=n,mp=0;
    	memset(f,0xc0,sizeof(f)),memset(g,0xc0,sizeof(g)),memset(h,0x3f,sizeof(h)),memset(k,0x3f,sizeof(k));
    	for(i=1;i<=m;i++)	x=s[i]=rd(),f[x][0]=g[x]=h[x][0]=k[x]=0,np=min(np,p[x]),mp=max(mp,p[x]);
    	top=1;
    	for(i=1;i<=n;i++)	if(p[i]<=np&&q[i]>=mp&&dep[i]>=dep[top])	top=i;
    	for(i=n;i>=2;i--)
    	{
    		x=Q[i],y=fa[x],d=dep[x]-dep[y];
    		if(f[y][0]>f[x][0]+d)	f[y][1]=max(f[y][1],f[x][0]+d);
    		else	f[y][1]=f[y][0],f[y][0]=f[x][0]+d;
    		if(!h[x][0]&&x!=top)	h[y][0]=0,ans+=(dep[x]-dep[y])<<1;
    		if(h[y][0]<h[x][0]+d)	h[y][1]=min(h[y][1],h[x][0]+d);
    		else	h[y][1]=h[y][0],h[y][0]=h[x][0]+d;
    	}
    	for(i=2;i<=n;i++)
    	{
    		x=Q[i],y=fa[x],d=dep[x]-dep[y],g[x]=max(g[x],g[y]+d),k[x]=min(k[x],k[y]+d);
    		if(f[y][0]==f[x][0]+d)	g[x]=max(g[x],f[y][1]+d);
    		else	g[x]=max(g[x],f[y][0]+d);
    		if(h[y][0]==h[x][0]+d)	k[x]=min(k[x],h[y][1]+d);
    		else	k[x]=min(k[x],h[y][0]+d);
    	}
    	for(i=1;i<=n;i++)	printf("%lld
    ",ans+2*min(k[i],h[i][0])-max(g[i],f[i][0]));
    	return 0;
    }
  • 相关阅读:
    Java 集合 — ArrayList
    Java 线程 — ScheduledThreadPoolExecutor
    Java 线程 — ThreadPoolExecutor
    Java 线程 — ThreadLocal
    Java 线程 — ConcurrentLinkedQueue
    Java 线程 — ConcurrentHashMap
    Java 线程 — AbstractQueuedSynchronizer
    Java 线程 — JMM Java内存模型
    Java 线程 — synchronized、volatile、锁
    spring源码 — 三、AOP代理生成
  • 原文地址:https://www.cnblogs.com/CQzhangyu/p/7514532.html
Copyright © 2011-2022 走看看