啊啊啊啊啊啊啊啊考场上差一点就A掉了5555

千里之堤溃于蚁穴……鬼知道最后一步那么显然的柿子我为什么没考虑用上……

观察数据范围可知,出题人期望我们想出一个$O(n)$的做法

当然也有可能是$O(nlogn)$,但是这道题所求的数值与树上每个点的权值有关,

似乎用点分治并不能够解决。

那怎么办?树形dp啊。保证严格$O(n)$。

有了这样的思路,我们先来看第一问,并设计一个可以用一遍dfs计算出数组$b[]$的算法。

各位想必知道,树形dp的基本思想是$"Up\ and\ Down"$,

而在最近的比赛和专题中,我们似乎见的大部分这类问题都是先向下dfs到底,再从下往上更新父亲的$dp[]$信息。

但是不要忘了另外一种啊喂……这题先不说从下往上能不能转移,就是起始更新点的初值你都没法$O(n)$以内算……

如果从上往下,用父亲更新儿子就十分好考虑了。

首先,起始点即为根节点,初值用一遍dfs即可算出。

之后考虑怎么转移。假设我们已知$b[2]$,要求它的儿子5的$b[]$,

这时候先来想一下$O(n^2)$的做法,即对于每个节点都跑一遍dfs,它究竟输在了哪里?

显然,有边相连的两点的$b[]$是有关系的,可以通过某种方式转化,而不必每次遍历整棵树进行冗余计算。

从2到5,5的子树(包含5本身)对于$b[]$的贡献都少了1,而5的子树之外的部分对它的贡献都多了1,

再通俗一点,我们把5的子树的贡献写出来:$b[2]=a_5+2*a_{10}+2*a_{11}...(之后就是5的子树之外的部分)$

而$b[5]=a_5*0+1*a_{10}+1*a_{11}+...$

看见没有?系数都少了1!子树外的部分同理。

那么一棵子树的贡献可以看作它内部点的权值和,第一遍dfs的时候就能预处理完毕。设它为$sum[]$。

易得:$b[y]=b[x]-sum[y]+sum[1]-sum[y]=b[x]+sum[1]-sum[y]*2$

第一问解决。

得出上面那个式子之后,第二问也就非常显然了。

我们把$b[x]$移到左侧,得到$b[y]-b[x]=sum[1]-sum[y]*2$

设$dt[y]=b[y]-b[x]$,这玩意相当于题里已经给了可以马上算出来。(当然$dt[1]$肯定求不出来)

先求出每个点的$dt[y]=sum[1]-sum[y]*2$,之后想怎么能够消元。

显然,$b[1]=\sum \limits _{i=2}^{n} sum[i]$

什么?并不显然?自己手玩去!

然后我们令$total=\sum \limits _{i=2}^{n}{dt[i]}=(n-1)sum[1]-2*\sum \limits_{i=2}^{n}{sum[i]}$

发现了什么?因为$b[1]$是已知量,所以可以把$total$减号后面的部分消掉!

$sum[1]$就求出来辣!

又因为所有的$dt[]$都是已知的,所有的$sum[]$就都可以求出来了。

至于$a[]$?再来一遍dfs就行了。

不得不说这道题真的很棒,没有特别难的知识点,整体难度也不太高,

但是很考验选手对于树上信息的处理能力和转化能力,以及基本的数学素养。

部分分也给的很合理,还能考察一下高斯消元。

还在犹豫什么?还不快来%%%% @liu_runda (逃

#include<cstdio>
#include<iostream>
#include<cstring>
using namespace std;
const int N=100005;
typedef long long ll;
int read()
{int x=0,f=1;char ch=getchar();while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}while(ch>='0'&&ch<='9')x=x*10+ch-'0',ch=getchar();return x*f;
}
int to[N<<1],nxt[N<<1],tot,head[N],num[N],sum[N],dep[N];
int dt[N];
int T,n,op;
int dp[N];
void add(int x,int y)
{to[++tot]=y;nxt[tot]=head[x];head[x]=tot;
}
void pre(int x,int deep)
{sum[x]=num[x];dep[x]=deep;for(int i=head[x];i;i=nxt[i]){int y=to[i];if(dep[y]||y==1)continue;pre(y,deep+1);sum[x]+=sum[y];}
}
void dfs(int x)
{for(int i=head[x];i;i=nxt[i]){int y=to[i];if(dep[y]<dep[x])continue;dp[y]=dp[x]-sum[y]+sum[1]-sum[y];dfs(y);}
}
void DFS(int x,int f)
{for(int i=head[x];i;i=nxt[i]){int y=to[i];if(y==f)continue;dt[y]=dp[y]-dp[x];DFS(y,x);}
}
void cacl()
{for(int i=1;i<=n;i++)num[i]=read();pre(1,0);for(int i=1;i<=n;i++)dp[1]+=dep[i]*num[i];dfs(1);for(int i=1;i<=n;i++)printf("%d ",dp[i]);printf("\n");
}
void getans(int x,int f)
{ll ssum=0;for(int i=head[x];i;i=nxt[i]){int y=to[i];if(y==f)continue;getans(y,x);ssum+=sum[y];}num[x]=sum[x]-ssum;
}
void solve()
{for(int i=1;i<=n;i++)dp[i]=read();DFS(1,0);ll total=0;for(int i=2;i<=n;i++)total+=1LL*dt[i];sum[1]=1LL*(dp[1]*2+total)/(n-1);for(int i=2;i<=n;i++)sum[i]=(-dt[i]+sum[1])/2;getans(1,0);for(int i=1;i<=n;i++)printf("%d ",num[i]);printf("\n");
}
void ini()
{for(int i=1;i<=n*2;i++){to[i]=nxt[i]=0;if(i<=n)dp[i]=dt[i]=head[i]=sum[i]=num[i]=dep[i]=0;}tot=0;
}
void work()
{n=read();ini();for(int i=1;i<n;i++){int x=read(),y=read();add(x,y);add(y,x);}op=read();if(op)solve();else cacl();
}
int main()
{T=read();while(T--)work();return 0;
}

View Code

UPD:附赠两组样例

1
6
1 2
1 3
2 4
2 5
3 6
0
4 2 3 5 6 11
6
1 2
1 3
2 4
2 5
3 6
1
29 24 42 35 33 61

Sample

两组是对称的(一组输入为另一组输出)

转载于:https://www.cnblogs.com/Rorschach-XR/p/11255318.html

[20190727NOIP模拟测试9]单(single) 题解(树上dp)相关推荐

  1. [NOIP模拟测试3] 建造游乐园 题解(欧拉图性质)

    Orz 出题人石二队爷 我们可以先求出有n个点的联通欧拉图数量,然后使它删或增一条边得到我们要求的方案 也就是让它乘上$C_n^2$ (n个点里选2个点,要么删边要么连边,选择唯一) 那么接下来就是求 ...

  2. [NOIP模拟测试9]题(Problem) 题解 (组合数全家桶+dp)

    达哥送分给我我都不要,感觉自己挺牛批. $type=0:$ 跟visit那题类似,枚举横向移动的步数直接推公式: $ans=\sum C_n^i \times C_i^{\frac{i}{2}} \t ...

  3. 2018冬令营模拟测试赛(十八)

    2018冬令营模拟测试赛(十八) [Problem A]Table 试题描述 输入 见"试题描述" 输出 见"试题描述" 输入示例 见"试题描述&qu ...

  4. 2018冬令营模拟测试赛(九)

    2018冬令营模拟测试赛(九) [Problem A]王子 试题描述 不是所有王子都会遇见自己的中关村,主公,公主. 从前有个王子姓王,王王子遇到了一位美丽的公主,她的名字当然是公公主啦. 王王子对公 ...

  5. 牛客网CSP-S提高组赛前集训营1题解(仓鼠的石子游戏 [博弈论] + 乃爱与城市的拥挤程度 [树上DP] + 小w的魔术扑克[dfs + 离线])

    文章目录 T1:仓鼠的石子游戏 题目 题解 代码实现 T2:乃爱与城市拥挤程度 题目 题解 代码实现 T3:小w的魔术扑克 题目 题解 代码实现 T1:仓鼠的石子游戏 题目 仓鼠和兔子被禁止玩电脑,无 ...

  6. NOIP模拟测试19「count·dinner·chess」

    反思: 我考得最炸的一次 怎么说呢?简单的两个题0分,稍难(我还不敢说难,肯定又有人喷我)42分 前10分钟看T1,不会,觉得不可做,完全不可做,把它跳了 最后10分钟看T1,发现一个有点用的性质,仍 ...

  7. php代码练习,PHP模拟测试练习

    PHP模拟测试练习 宝剑不磨要生锈;人不学习要落后.以下是小编为大家搜索整理的PHP模拟测试练习,希望能给大家带来帮助!更多精彩内容请及时关注我们应届毕业生考试网! 一.单项选择题 1.下列哪些是PH ...

  8. JS模拟Form表单提交

    用java写了一个下载的功能,测试没有问题,但前台就是不弹出下载的提示框. 后来发现如果你的提交方式是ajax的方式的话是不会弹出提示框的,然后换成了form提交,顺利弹框通过,下来我们就用js模拟f ...

  9. 773-780---DOM事件高级(常用鼠标事件,案例:跟随鼠标的天使,常用的键盘事件,案例:模拟京东按键输入内容,案例:模拟京东快递单号查询)

    文章目录 事件高级 7 常用的鼠标事件 7.1常用的鼠标事件 7.2 鼠标事件对象 案例:跟随鼠标的天使 8 常用的键盘事件 8.1 常用的键盘事件 8.2 键盘事件对象 8.3 ASCII 表 案例 ...

最新文章

  1. Mac OS X 在Finder新建文本文件
  2. 2019-11-10 等价、相似、合同的一些概念
  3. RabbitMQ延迟消息的极限是多少?
  4. java文件复制(可过滤)
  5. binlog2sql闪回恢复数据
  6. iOS中的三大定时器
  7. 应用统计学学什么科目_统计学考研初试都要考哪些科目?
  8. 【电信学】【2019.07】基于ATOLL的5G网络规划与优化
  9. python编程 个人所得税计算器
  10. docker+scrapy+scrapy_splash爬取大麦网
  11. 机器学习(8)——回归和异常值处理(安然数据集)
  12. 八皇后算法—java
  13. Ubuntu安装opencv的viz模块
  14. PHP---保留小数并且(不)四舍五入
  15. 舒亦梵:这十个小技巧,教你炒黄金长久获利
  16. 英雄联盟比分直播网/APP定制开发英雄联盟数据源码
  17. IDEA2019 Java连接PostgreSQL数据库实现基础功能增删改查
  18. [机器学习与scikit-learn-51]:模型评估-图解回归模型的评估指标MSE、MAE、RMSE、R2、RSS与代码示例
  19. 如何用计算机算利率,信用卡怎么算的利息怎么算的?信用卡利息计算器
  20. 备战专升本的日常0903-0917

热门文章

  1. BgSub 无需上传图片即可在线自动抠图的AI工具
  2. 【Windows Server 2019】路由服务的配置和管理
  3. larval容器,服务提供者,门面案例
  4. 2012年河北金融学院csdn招新动员大会
  5. 西门子200系列PLC通信编程指令讲解
  6. 华为路由器接口IP地址如何配置与查看
  7. 【有利可图网】PS教程:制造低多边形熊猫头像
  8. Invalid row number (65536) outside allowable range (0..65535)
  9. 面试时,如何正确表现自己的实力?
  10. 西门子S7200plc通信不上实际问题和解决方法