您的位置:首页 > 其它

bzoj1060[ZJOI2007] 时态同步

2017-03-11 23:18 253 查看
题目链接:bzoj1060

题目大意:

有一棵n个节点的以s为根的树。通过一条树边需要一定的时间。一次操作可以让一条树边的通过时间增加1。问最少要多少次操作可以使得从根出发到各个叶子节点的时间是一样的。

题解:

treedp

这道题挺简单的。就是我一开始sb了一下。弄错了点东西。搞得还要对拍调一发(虽然也没多久

因为最后要使到达所有叶子节点的时间一样嘛,所以对于每个节点x来说,就要保证从它开始走到它子树中的叶子节点的时间也一样,我们设这个时间为tim[x]。要让操作次数最少,即使tim[x]越小越好,即令tim[x]=max(tim[y]+c)。这样就可以保证在时间一样的条件下,操作次数最少了。所以在枚举儿子的时候只要看看从x走到那个子树的叶子的时间是不是比当前的tim[x]要多,如果是的话就改tim[x]并对ans贡献 走过的子树的个数 个 差值;反之,只要贡献一个差值就好了。

不知道要怎么扯淡了。╮(╯▽╰)╭语文水平不好,还不懂看代码吧

#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
typedef long long LL;
#define maxn 500100

struct node
{
LL x,y,c,next;
}a[maxn*2];LL len,first[maxn];
LL tim[maxn],ans;
void ins(LL x,LL y,LL c)
{
len++;a[len].x=x;a[len].y=y;
a[len].c=c;a[len].next=first[x];first[x]=len;
}
void treedp(LL x,LL fa)
{
int num=0;tim[x]=0;
for (LL k=first[x];k!=-1;k=a[k].next)
{
LL y=a[k].y;
if (y==fa) continue;
treedp(y,x);
tim[y]+=a[k].c;
if (tim[x]<tim[y])
{
ans+=num*(tim[y]-tim[x]);
tim[x]=tim[y];
}else ans+=tim[x]-tim[y];
num++;
}
}
int main()
{
LL n,st,i,x,y,c;
scanf("%lld%lld",&n,&st);
len=0;memset(first,-1,sizeof(first));
for (i=1;i<n;i++)
{
scanf("%lld%lld%lld",&x,&y,&c);
ins(x,y,c);ins(y,x,c);
}
ans=0;treedp(st,0);
printf("%lld\n",ans);
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: