BZOJ 3727 PA2014 Final Zadanie 树形DP

题目大意:给定一棵树,令一个点到所有点的距离与点权的乘积之和为b[i],求每个点的权值a[i]

首先如果给定a[i]我们可以很轻松的求出b[i] 但是反过来怎么搞?高斯消元?30W?

考虑已知a[i]求b[i]的情况 令这棵树的根为1 点i到根节点的距离为dis[i] 以i为根的子树的a值之和为size[i] 那么有递推式

b[1]=Σa[i]*dis[i]

b[x]=b[fa[x]]-2*size[x]+size[1]

将上式变形得:

2*size[x]=b[fa[x]]-b[x]+size[1]

且显然有

a[x]=size[x]-Σa[son[x]]

我们可以O(n)求出所有a[x]关于size[1]的一次函数关系 然后代入b[1]=Σa[i]*dis[i] 可以得到b[1]关于size[1]的一次函数关系 由于b[1]已知 所以size[1]就搞出来了

然后代入求出a[2]~a[n] 然后用size[1]减掉所有的a[2]~a[n]就是a[1]

别忘了开long long

多解啥的 看到没有Special Judge就知道 那是逗你的……

#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#define M 300300
using namespace std;
typedef long long ll;
typedef pair<ll,ll> abcd;
struct edge{
	int to,next;
}table[M<<1];
int head[M],tot;
int n,ans,fa[M],dis[M];
ll a[M],b[M];
abcd double_size[M],double_a[M],b_1;
void Add(int x,int y)
{
	table[++tot].to=y;
	table[tot].next=head[x];
	head[x]=tot;
}
abcd operator += (abcd &x,const abcd &y)
{
	x.first+=y.first;
	x.second+=y.second;
}
void operator -= (abcd &x,const abcd &y)
{
	x.first-=y.first;
	x.second-=y.second;
}
abcd operator * (const abcd &x,int y)
{
	return abcd( x.first * y , x.second * y );
}
void BFS()
{
	static int q[M],r,h;
	int i;
	q[++r]=1;
	while(r!=h)
	{
		int x=q[++h];
		for(i=head[x];i;i=table[i].next)
			if(table[i].to!=fa[x])
			{
				fa[table[i].to]=x;
				dis[table[i].to]=dis[x]+1;
				q[++r]=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);
	for(i=1;i<=n;i++)
		scanf("%d",&b[i]);
	BFS();
	for(i=2;i<=n;i++)
		double_size[i]=abcd(1,b[fa[i]]-b[i]);
	for(x=2;x<=n;x++)
	{
		double_a[x]=double_size[x];
		for(i=head[x];i;i=table[i].next)
			if(table[i].to!=fa[x])
				double_a[x]-=double_size[table[i].to];
		b_1+=double_a[x]*dis[x];
	}
	ans=(b[1]+b[1]-b_1.second)/b_1.first;
	a[1]=ans;
	for(i=2;i<=n;i++)
	{
		a[i]=double_a[i].first*ans+double_a[i].second>>1;
		a[1]-=a[i];
	}
	for(i=1;i<=n;i++)
		printf("%lld%c",a[i],i==n?'\n':' ');
}
+
时间: 2024-10-29 12:56:12

BZOJ 3727 PA2014 Final Zadanie 树形DP的相关文章

BZOJ 3727 PA2014 Final Zadanie 贪心

题目大意:给定n个数,多次询问选择k个数使和为奇数的最大和 首先将所有数排序 对于每个询问,如果最大的k个数之和是奇数,那么答案显然是这k个数的和 如果最大的k个数之和是偶数,那么我可以将后k个数中最小的偶数换成前n-k个数中最大的奇数,或者将后k个数中最小的奇数换成前n-k个数中最大的偶数 二者取最优即可 无法如此做则输出-1 #include <cstdio> #include <cstring> #include <iostream> #include <a

【BZOJ 3727】 3727: PA2014 Final Zadanie (递推)

3727: PA2014 Final Zadanie Time Limit: 10 Sec  Memory Limit: 128 MBSubmit: 279  Solved: 121 Description 吉丽YY了一道神题,题面是这样的:"一棵n个点的树,每条边长度为1,第i个结点居住着a[i]个人.假设在i结点举行会议,所有人都从原住址沿着最短路径来到i结点,行走的总路程为b[i].输出所有b[i]."吉丽已经造好了数据,但熊孩子把输入文件中所有a[i]给删掉了.你能帮他恢复吗?

[BZOJ 4033] [HAOI2015] T1 【树形DP】

题目链接:BZOJ - 4033 题目分析 使用树形DP,用 f[i][j] 表示在以 i 为根的子树,有 j 个黑点的最大权值. 这个权值指的是,这个子树内部的点对间距离的贡献,以及 i 和 Father[i] 之间的边对答案的贡献(比如这条边对黑点对距离和的贡献就是子树内部的黑点数 * 子树外部的黑点数 * 这条边的权值). 然后DFS来求,枚举 i 的每个儿子 j,现在的 f[i][] 是包含了 [1, j-1] 子树,然后两重循环枚举范围是 [1, j - 1] 的子树总 Size 和

bzoj 3566: [SHOI2014]概率充电器 树形DP

首先普及一个概率公式 P(A+B)=P(A)+P(B)-P(AB) 题意:一些充电元件和导线构成一棵树,充电元件是否能充电有2种情况, 1.它自己有qi%的概率充电 2.与它相邻的元件通过导线给它充电(导线有p%的概率导通) 求最终充了电的元件的期望 题解:首先可以将元件能否充电分成3种情况考虑, 1.它自己给自己充好了电 2.它的儿子方向给它传送了电 3.它的父亲方向给它传送了电. 对于1,题目已经给出可以直接赋值, 对于2,可以通过一次树的深度遍历求得.pson[now]=pson[now]

BZOJ 2878([Noi2012]迷失游乐园-树形DP+环加外向树+期望DP+vector的erase)

2878: [Noi2012]迷失游乐园 Time Limit: 10 Sec  Memory Limit: 512 MBSec  Special Judge Submit: 319  Solved: 223 [Submit][Status] Description 放假了,小Z觉得呆在家里特别无聊,于是决定一个人去游乐园玩.进入游乐园后,小Z看了看游乐园的地图,发现可以将游乐园抽象成有n个景点.m条道路的无向连通图,且该图中至多有一个环(即m只可能等于n或者n-1).小Z现在所在的大门也正好是

BZOJ 2878: [Noi2012]迷失游乐园( 树形dp )

一棵树的话直接树形dp(求出往下走和往上走的期望长度). 假如是环套树, 环上的每棵树自己做一遍树形dp, 然后暴力枚举(环上的点<=20)环上每个点跑经过环上的路径就OK了. --------------------------------------------------------------------------------------------- #include<cstdio> #include<cstring> #include<algorithm&

BZOJ 2435 道路修建 NOI2011 树形DP

一看到这道题觉得很水,打了递归树形DP后RE了一组,后来发现必须非递归(BFS) 递归版本84分: #include<cstdio> #include<cstring> #include<algorithm> using namespace std; int N,point[1000003],next[2000003],v[2000003],c[2000003],cnt=0,f[1000003]; bool p[1000003]; long long sum=0; vo

BZOJ 2314: 士兵的放置( 树形dp )

树形dp... dp(x, 0)表示结点x不放士兵, 由父亲控制: dp(x, 1)表示结点x不放士兵, 由儿子控制: dp(x, 2)表示结点x放士兵. ------------------------------------------------------------------------------------- #include<cstdio> #include<cstring> #include<algorithm> using namespace st

BZOJ 2286 消耗战 (虚树+树形DP)

给出一个n节点的无向树,每条边都有一个边权,给出m个询问,每个询问询问ki个点,问切掉一些边后使得这些顶点无法与顶点1连接.最少的边权和是多少.(n<=250000,sigma(ki)<=500000) 考虑树形DP,我们令mn[i]表示i节点无法与1节点相连切除的最小权值.显然有mn[i]=min(E(fa,i),mn[fa]).大致就是i到1的简单路径上的最小边.我们对于每个询问.把询问的点不妨称为关键点.令dp[i]表示i节点不能与子树的关键点连接切掉的最小权值.那么有,如果son[i]