【HNOI】 c tree-dp
【题目描述】给定一个n个节点的树,每个节点有两个属性值a[i],b[i],我们可以在树中选取一个连通块G,这个连通块的值为(Σa[x])(Σb[x]) x∈G,求所有连通块的值的和,输出答案对1000000007取余。
【数据范围】n<=10^5.
首先我们任选一个点作为根,变成一颗有根树。观察答案为(Σa[x])(Σb[x]),那么我们可以将这个答案展开成为每一个b[x]乘上所有可能情况下的a[y],这个可能情况就是x点在连通块中时,b[x]乘上连通块内所有点的a值去和,再枚举所有的连通块,就可以求出来b[x]对答案的贡献,那么我们现在问题就转化为了求出来一个节点,所有包括这个节点的连通块的a值和,每个连通块的a值为连通块内所有点的a值和,设这个值为sum_[x]。
我们的sum_[x]的值的求方法可以为x子树中每个a被累加的次数加上非x子树节点a值被累加的次数,那么我们可以依次求出来这两个,然后求出sum_[x]。
我们设w[x]为以x为根的子树中,包含x节点的连通块的数量,sum[x]为以x为根的子树中,包含x的所有连通块的a值和,w_[x]为所有包含x节点的连通块的数量。
有了这些量,我们就可以求出sum_[x],先考虑这些量的转移。
w[x]=π(w[son of x]+1).
sum[x]=Σ(w[x]/(w[son of x]+1)*sum[son of x]).
这两个量的转移是由子节点到根的,比较容易考虑,现在我们有了这两个量之后,考虑用这两个量转移其余的两个量。
w_[x]=(w_[father of x]/(w[x]+1)+1)*w[x].
那么sum_[x]就等于之前说的两部分相加,则
sum_[x]=w_[father of x]/(w[x]+1)+1)*sum[x]+(sum_[father of x]-w_[father of x]/(w[x]+1)*sum[x])/(w[x]+1)*w[x].
反思:为了提高速度没开LL,用到的地方强转的LL,然后有的地方忘加了,纠结了好久= =。
//By BLADEVIL
#include <cstdio>
#define d39 1000000007
#define maxn 100010
#define LL long long using namespace std; int n,l;
int last[maxn],other[maxn<<],pre[maxn<<],a[maxn],b[maxn],que[maxn],dis[maxn];
int sum[maxn],w[maxn],sum_[maxn],w_[maxn]; void connect(int x,int y) {
pre[++l]=last[x];
last[x]=l;
other[l]=y;
} int pw(int x,int k) {
int ans=;
while (k) {
if (k&) ans=((LL)ans*x)%d39;
x=((LL)x*x)%d39;
k>>=;
}
return ans;
} int main() {
freopen("c.in","r",stdin); freopen("c.out","w",stdout);
scanf("%d",&n);
for (int i=;i<n;i++) {
int x,y; scanf("%d%d",&x,&y);
connect(x,y); connect(y,x);
}
for (int i=;i<=n;i++) scanf("%d",&a[i]);
for (int i=;i<=n;i++) scanf("%d",&b[i]);
int h=,t=; que[]=; dis[]=;
while (h<t) {
int cur=que[++h];
for (int p=last[cur];p;p=pre[p]) {
if (dis[other[p]]) continue;
que[++t]=other[p]; dis[other[p]]=dis[cur]+;
}
}
//for (int i=1;i<=n;i++) printf("%d ",que[i]); printf("\n");
for (int i=n;i;i--) {
int cur=que[i];
w[cur]=;
for (int p=last[cur];p;p=pre[p]) {
if (dis[other[p]]<dis[cur]) continue;
w[cur]=((LL)w[cur]*(w[other[p]]+))%d39;
}
sum[cur]=((LL)w[cur]*a[cur])%d39;
for (int p=last[cur];p;p=pre[p]) {
if (dis[other[p]]<dis[cur]) continue;
sum[cur]=(sum[cur]+((LL)((LL)w[cur]*pw(w[other[p]]+,d39-)%d39)*sum[other[p]])%d39)%d39;
}
}
//for (int i=1;i<=n;i++) printf("%d %d %d\n",i,sum[i],w[i]);
for (int i=;i<=n;i++) {
int cur=que[i];
if (cur==) {
w_[cur]=w[cur];
sum_[cur]=sum[cur];
}
for (int p=last[cur];p;p=pre[p]) {
if (dis[other[p]]<dis[cur]) continue;
//printf("%d\n",pw(w_[cur]*w[other[p]]+1,d39-2)%d39);
int tot=(LL)w_[cur]*pw(w[other[p]]+,d39-)%d39;
//printf("%d\n",tot);
w_[other[p]]=((LL)(tot+)%d39*w[other[p]]%d39);
sum_[other[p]]=((LL)(tot+)*sum[other[p]]%d39+(LL)((LL)(sum_[cur]-(LL)tot*sum[other[p]]%d39+d39))%d39*w[other[p]]%d39*pw(w[other[p]]+,d39-)%d39)%d39;
}
}
//for (int i=1;i<=n;i++) printf("%d %d %d %d\n",i,w[i],sum[i],sum_[i]);
int ans=;
for (int i=;i<=n;i++) ans=(ans+(LL)sum_[i]*b[i])%d39;
printf("%d\n",ans);
fclose(stdin); fclose(stdout);
return ;
}
【HNOI】 c tree-dp的更多相关文章
- 【BZOJ】2631: tree LCT
		
[题意]给定n个点的树,每个点初始权值为1,m次操作:1.x到y的点加值,2.断一条边并连一条边,保证仍是树,3.x到y的点乘值,4.x到y的点权值和取模.n,m<=10^5. [算法]Link ...
 - 【BZOJ2212】[Poi2011]Tree Rotations 线段树合并
		
[BZOJ2212][Poi2011]Tree Rotations Description Byteasar the gardener is growing a rare tree called Ro ...
 - 【题解】Digit Tree
		
[题解]Digit Tree CodeForces - 716E 呵呵以为是数据结构题然后是淀粉质还行... 题目就是给你一颗有边权的树,问你有多少路径,把路径上的数字顺次写出来,是\(m\)的倍数. ...
 - 【题解】POJ1934 Trip (DP+记录方案)
		
[题解]POJ1934 Trip (DP+记录方案) 题意: 传送门 刚开始我是这么设状态的(谁叫我DP没学好) \(dp(i,j)\)表示钦定选择\(i\)和\(j\)的LCS,然而你会发现这样钦定 ...
 - 【题解】[P4178 Tree]
		
[题解]P4178 Tree 一道点分治模板好题 不知道是不是我见到的题目太少了,为什么这种题目都是暴力开值域的桶QAQ?? 问点对,考虑点分治吧.直接用值域树状数组开下来,统计的时候直接往树状数组里 ...
 - 【HNOI】合唱队
		
[HNOI]合唱队 题意 对于一个初始序列,保证两两不同,通过一些变换得到目标序列: 第一个值直接插入空的当前队列 对于从第二个值开始的每个值 如果原序列中 $ a[i] $,若 $ a[i]> ...
 - 【题解】剪纸条(dp)
		
[题解]剪纸条(dp) HRBUST - 1828 网上搜不到题解?那我就来写一篇吧哈哈哈 最优化问题先考虑\(dp\),设\(dp(i)\)表示将前\(i\)个字符(包括\(i\))分割成不相交的回 ...
 - 【题解】地精部落(DP)
		
[题解]地精部落(DP) 设\(f_i\)表示强制第一个是谷的合法方案数 转移枚举一个排列的最大值在哪里,就把序列分成了互不相干的两个部分,把其中\(i-1\choose j-1\)的数字分配给前面部 ...
 - 【BZOJ-1068】压缩       区间DP
		
1068: [SCOI2007]压缩 Time Limit: 1 Sec Memory Limit: 128 MBSubmit: 1001 Solved: 615[Submit][Status][ ...
 - 【BZOJ-1492】货币兑换Cash       DP + 斜率优化 + CDQ分治
		
1492: [NOI2007]货币兑换Cash Time Limit: 5 Sec Memory Limit: 64 MBSubmit: 3396 Solved: 1434[Submit][Sta ...
 
随机推荐
- 【Docker 命令】- inspect命令
			
docker inspect : 获取容器/镜像的元数据. 语法 docker inspect [OPTIONS] NAME|ID [NAME|ID...] OPTIONS说明: -f :指定返回值的 ...
 - 【Python】python文件名和文件路径操作
			
Readme: 在日常工作中,我们常常涉及到有关文件名和文件路径的操作,在python里的os标准模块为我们提供了文件操作的各类函数,本文将分别介绍“获得当前路径”“获得当前路径下的所有文件和文件夹, ...
 - 【bzoj3427】Poi2013 Bytecomputer  dp
			
题目描述 A sequence of N integers I1,I2…In from the set {-1,0,1} is given. The bytecomputer is a device ...
 - pascal语言中学版整理
			
P1:主菜单File中的Command shell选项,可以暂时退出Pascal,进入DOS提示符状态,但Pascal仍然驻留在内存中.输入命令exit即可返回Pascal. P3:Edit菜单中Un ...
 - Dom样式操作-属性操作
			
1. 对样式进行操作: 1) 以样式(C1,C2等)为最小单位进行修改. className, classList, (以列表形式获得) classList.add("C2"), ...
 - POJ1474:Video Surveillance——题解
			
http://poj.org/problem?id=1474 题目大意:给按照顺时针序的多边形顶点,问其是否有内核. —————————————————————————————— (和上道题目一模一样 ...
 - BZOJ3236:[AHOI2013]作业——题解
			
https://www.lydsy.com/JudgeOnline/problem.php?id=3236 第一种做法: 建两棵主席树分别处理两个问题. 第一个问题水,第二个问题参考SPOJ3267/ ...
 - 从零开始学Linux系统(二)之基本操作指令
			
ifconfigping ip地址帮助:ping -t ip地址ping -c 次数 ip地址ping -s 包的大小关机重启:shutdown -h now reboot清屏:clear == C ...
 - 浅谈Hibernate框架(一)——.hbm.xml中的配置
			
Hibernate一枚“全自动”的ORM框架: 用IDE工具集成Hibernate会自动生成: 以.hbm.xml为后缀结尾的配置文件+ POJO类 + Dao类 主键查询: Session.load ...
 - 调整KVM虚拟机硬盘大小
			
KVM虚拟机的硬盘映像默认存放在“/var/lib/libvirt/images/”中,先查看你的硬盘映像格式是不是RAW格式: qemu-img info /var/lib/libvirt/imag ...