BZOJ 1131 POI2008 Sta 树形DP

题目大意:给定一个n个点的无根树,要求找到一个根节点,使深度之和最大

令f[x]为以x为根的子树的深度之和

首先我们找到任意一个节点进行深搜,统计出每棵子树的大小,以及所有点的深度之和

然后再以该节点为根深搜一遍,此时状态从父节点转移至子节点,转移方程如下:

当我们将根节点从4节点变为5节点时,橙色部分每个点的深度+1,绿色部分每个点的深度-1

故得到状态转移方程:

f[x]=f[fa[x]]+n-2*size[x]

最后扫一遍数组即可出解

#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#define M 1001001
using namespace std;
typedef long long ll;
struct abcd{
	int to,next;
}table[M<<1];
int head[M],tot;
int n,ans,fa[M],siz[M];
ll f[M];
//根节点深度为0
void Add(int x,int y)
{
	table[++tot].to=y;
	table[tot].next=head[x];
	head[x]=tot;
}
void DFS1(int x)
{
	int i;
	siz[x]=1;
	for(i=head[x];i;i=table[i].next)
	{
		if(table[i].to==fa[x])
			continue;
		fa[table[i].to]=x;
		DFS1(table[i].to);
		siz[x]+=siz[table[i].to];
		f[x]+=f[table[i].to]+siz[table[i].to];
	}
}
void DFS2(int x)
{
	int i;
	if(x!=1)
		f[x]=f[fa[x]]+n-siz[x]-siz[x];
	for(i=head[x];i;i=table[i].next)
	{
		if(table[i].to==fa[x])
			continue;
		DFS2(table[i].to);
	}
}
int main()
{
	int i,x,y;
	cin>>n;
	for(i=1;i<n;i++)
	{
		scanf("%d%d",&x,&y);
		Add(x,y);
		Add(y,x);
	}
	DFS1(1);
	DFS2(1);
	for(i=1;i<=n;i++)
		if(f[i]>f[ans])
			ans=i;
	cout<<ans<<endl;
}
时间: 2024-11-03 21:48:11

BZOJ 1131 POI2008 Sta 树形DP的相关文章

BZOJ 1131: [POI2008]Sta

1131: [POI2008]Sta Time Limit: 10 Sec  Memory Limit: 162 MBSubmit: 1370  Solved: 486[Submit][Status][Discuss] Description 给出一个N个点的树,找出一个点来,以这个点为根的树时,所有点的深度之和最大 Input 给出一个数字N,代表有N个点.N<=1000000 下面N-1条边. Output 输出你所找到的点,如果具有多个解,请输出编号最小的那个. Sample Input

1131: [POI2008]Sta

1131: [POI2008]Sta Time Limit: 10 Sec  Memory Limit: 162 MBSubmit: 783  Solved: 235[Submit][Status] Description 给出一个N个点的树,找出一个点来,以这个点为根的树时,所有点的深度之和最大 Input 给出一个数字N,代表有N个点.N<=1000000 下面N-1条边. Output 输出你所找到的点,如果具有多个解,请输出编号最小的那个. Sample Input 8 1 4 5 6

BZOJ 4033 HAOI2015 T1 树形DP

题目大意:给定一棵树,你需要把其中的k个点染成黑色,使得黑色点两两之间的距离和+白色点两两之间的距离和最大,求最大值 题解戳这里 Orz ydcydc 看来我对于非线性的树形DP还是做得太少了QwQ #include <cstdio> #include <cstring> #include <iostream> #include <algorithm> #define M 2020 using namespace std; struct edge{ int

BZOJ 1017--魔兽地图(树形DP&amp;完全背包)

1017: [JSOI2008]魔兽地图DotR Time Limit: 30 Sec  Memory Limit: 162 MBSubmit: 2674  Solved: 1041[Submit][Status][Discuss] Description DotR (Defense of the Robots) Allstars是一个风靡全球的魔兽地图,他的规则简单与同样流行的地图DotA (Defense of the Ancients) Allstars.DotR里面的英雄只有一个属性——

BZOJ 1596--电话网络(树形DP)

1596: [Usaco2008 Jan]电话网络 Time Limit: 10 Sec  Memory Limit: 162 MBSubmit: 1139  Solved: 534[Submit][Status][Discuss] Description Farmer John决定为他的所有奶牛都配备手机,以此鼓励她们互相交流.不过,为此FJ必须在奶牛们居住的N(1 <= N <= 10,000)块草地中选一些建上无线电通讯塔,来保证任意两块草地间都存在手机信号.所有的N块草地按1..N 顺

BZOJ 1040: [ZJOI2008]骑士( 树形dp )

这是一个森林中, 每棵树上都有一个环...每棵树单独处理, 找出环上任意一条边断开, 限制一下这条边两端点的情况, 然后就可以树dp了.. ------------------------------------------------------------------------ #include<cstdio> #include<algorithm> #include<cstring> #include<cctype> using namespace

BZOJ 3829 Poi2014 FarmCraft 树形DP+贪心

题目大意:给定一棵树,从1号节点出发对树进行欧拉遍历,每到达一个点这个点就开始装MC,每个点装MC的时间不同,最后回到1号节点装MC,求所有人都能联机的最少时间 令f[x]为对第x个节点进行欧拉遍历的时间,g[x]为对第x个节点进行欧拉遍历并完成所有节点的装机的最小时间 那么在每个节点以什么顺序遍历每棵子树呢? 我们发现装机多出来的时间 即g[x]-f[x]可以用来遍历其它子树 那么显然要从g[x]-f[x]大的子树开始遍历 因此对每个节点的子树按照g[x]-f[x]递减排个序即可 时间复杂度O

BZOJ 3037 创世纪 树形DP

题目大意:给定一张有向图,每个点有且仅有一条出边,要求若一个点x扔下去,至少存在一个保留的点y,y的出边指向x,求最多扔下去多少个点 首先原题的意思就是支配关系 我们反向考虑 求最少保留的点 要求一个点若扔出去 则必须存在一个保留的点指向它 于是这就是最小支配集 不过由于是有向图 所以一个点要么选择 要么被子节点支配 所以就只剩下2个状态了 设f[x]为以x为根的子树选择x的最小支配集 g[x]为不选择x的最小支配集 然后由于是基环树林 所以我们选择一个环上的点 拆掉它的出边 设这个点为x 出边

[POI2008] STA-Station - 树形dp

很显然的递推式ans[q] = ans[p] + n - 2*siz[q]; 这么个题你卡我常干嘛,害得我加快读 (谁叫我是vector党呢 #include <bits/stdc++.h> using namespace std; #define int long long const int N = 1000006; inline int read(){ int s=0,w=1; char ch=getchar(); while(ch<'0'||ch>'9'){if(ch=='