【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 ...
随机推荐
- 3DMAX2016破解教程
首先,断网. 然后,下载3DMAX2016注册机. 然后,打开已经安装的3DMAX2016,会出现下图,点击激活按钮. 之后,以管理员身份打开3DMAX2016注册机,把申请号复制到注册机里面的请求码 ...
- CSS 经典三列布局
一 圣杯布局 1 html结构 <!DOCTYPE html> <html> <head> <title></title> <link ...
- grid++json页面数据传入
最近遇到一个问题,就是要用Grid++做页面数据报表打印,但是翻了Grid++文档就是没有直接从页面上传数据的,都是要加载txt文档,填写txt文档的url.自己尝试直接页面上传JSON数据到Grid ...
- win7主题/默认账户图片路径
账户图片位置 C:\ProgramData\Microsoft\User Account Pictures 主题位置 C:\Windows\Resources
- 【Json】Newtonsoft.Json高级用法
手机端应用讲究速度快,体验好.刚好手头上的一个项目服务端接口有性能问题,需要进行优化.在接口多次修改中,实体添加了很多字段用于中间计算或者存储,然后最终用Newtonsoft.Json进行序列化返回数 ...
- 【bzoj4196】[Noi2015]软件包管理器 树链剖分+线段树
题目描述 Linux用户和OSX用户一定对软件包管理器不会陌生.通过软件包管理器,你可以通过一行命令安装某一个软件包,然后软件包管理器会帮助你从软件源下载软件包,同时自动解决所有的依赖(即下载安装这个 ...
- Luogu3936 Coloring(模拟退火)
裸退火,每次交换两个格子即可.依旧不会调参,稍微抄了点参数并且把随机种子设成了一个神奇的数字终于过掉了. #include<iostream> #include<cstdio> ...
- NYOJ 1000 又见斐波那契数列
描述 斐波那契数列大家应该很熟悉了吧.下面给大家引入一种新的斐波那契数列:M斐波那契数列. M斐波那契数列F[n]是一种整数数列,它的定义如下: F[0] = a F[1] = b F[n] = F[ ...
- 【转】Unity+单例模式的依赖注入
http://www.cnblogs.com/floyd/archive/2009/06/17/1505117.html
- 【题解】洛谷P4735最大异或和
学习了一下可持久化trie的有关姿势~其实还挺好理解的,代码也短小精悍.重点在于查询某个历史版本的trie树上的某条边是否存在,同样我们转化到维护前缀和来实现.同可持久化线段树一样,我们为了节省空间继 ...