【题目描述】给定一颗树,每个点有各自的权值,任意选取两个点,要求算出这两个点路径上所有点的and,or,xor的期望值。

  【数据范围】n<=10^5

  首先期望可以转化为求树上所有点对的and,or,xor值的和,然后在除以n*n就可以了,对于权值,我们可以按位做,这样问题就转化为了给定一棵树,树上的点的权值为0或者1,我们需要求出来点对的and,or,xor值,这个问题我们可以取任意节点当做根,然后用tree-dp来解决

  and:这个比较好处理,我们只需要记录每个节点x,p为x子树中一点,x到p的路径上全部为1,这样的p的点的数量,这个比较容易转移,记录这个为sum,那么

    sum[x]=Σsum[p] col[x]==1

    sum[x]=0           col[x]==0  col为颜色。

    维护了这个东西之后我们就可以处理答案了,对于所有x的点对,有两种情况,第一种是一端点是x,另一端点是x子树中的点,对于这样的点,我们只需要累加sum[son of x]就可以了,因为x颜色可能是0,所以我们不能直接加sum[x],还有一种情况是这个点对在x的子树中,且路径经过x,那么这样的点对我们只需要记录一个tot代表Σsum[son of x]然后对于x的每一个子节点p,我们需要累加答案sum[p]*(tot-sum[p]),这样就可以了。

  or:维护一个num数组,设p为x的子树中一点,那么num[x]为所有x到p的路径上存在一个1的p的个数,设size[x]表示以x为根节点那么

    num[x]=size[x]     col[x]==1

    num[x]=Σnum[p]   col[x]==0

    这样我们就可以求出来num[x]了,对于答案的累加类似于and的累加,对于跨根的,我们只需要使路径的一部分有1就好了,也就是ans+=num[p]*(size[x]-size[p]-1)。

  xor:我们可以维护一个a0[x]和a1[x]代表以x为根的子树中,p为其中一点,x到p的路径上1的个数为奇/偶的p的点的数量,那么比较显然的是

    a0[x]=Σa1[p] a1[x]=Σa0[p]  col[x]==1  

    a0[x]=Σa0[p] a1[x]=Σa1[p]  col[x]==0

    这个的累加答案也类似于上面,我们需要用a0[p]和a1[p]来累加答案。

  反思:比赛的时候没考虑到然后栈溢出了,后来改成bfs就好了。

//By BLADEVIL
#include <cstdio>
#include <cstring>
#define maxn 100010
#define LL long long
#pragma comment(linker,"/STACK:102400000,102400000") using namespace std; LL n,l;
LL pre[maxn<<],other[maxn<<],last[maxn],key[maxn],color[maxn],sum[maxn],size[maxn],num[maxn],a0[maxn],a1[maxn],que[maxn],flag[maxn],father[maxn];
LL ans,ANS,ANSor,ansor,ANSx,ansx; void connect(LL x,LL y) {
//printf("%d %d %d\n",x,y,l);
pre[++l]=last[x];
last[x]=l;
other[l]=y;
} void update(LL x){
//printf("%d ",x);
sum[x]=color[x]; size[x]=; num[x]=;
if (color[x]) a1[x]=,a0[x]=; else a0[x]=,a1[x]=;
for (LL p=last[x];p;p=pre[p]) {
if (other[p]==father[x]) continue;
size[x]+=size[other[p]];
}
if (sum[x]) {
LL tot=;
for (LL p=last[x];p;p=pre[p]) if (other[p]!=father[x]) ans+=*sum[other[p]],tot+=sum[other[p]];
for (LL p=last[x];p;p=pre[p]) if (other[p]!=father[x]) ans+=sum[other[p]]*(tot-sum[other[p]]);
sum[x]+=tot;
}
if (color[x]) {
for (LL p=last[x];p;p=pre[p])
if (other[p]!=father[x]) ansor+=size[other[p]]*(size[x]-size[other[p]]);
num[x]=size[x];ansor+=num[x];
} else {
LL tot=size[x];
for (LL p=last[x];p;p=pre[p])
if (other[p]!=father[x]) ansor+=*num[other[p]]*(tot-size[other[p]]),num[x]+=num[other[p]],tot-=num[other[p]];
}
if (color[x]) {
LL tot0=,tot1=;
for (LL p=last[x];p;p=pre[p])
if (other[p]!=father[x]) tot0+=a0[other[p]],tot1+=a1[other[p]];
ansx+=*tot0+;
for (LL p=last[x];p;p=pre[p])
if (other[p]!=father[x]) ansx+=*a0[other[p]]*(tot0-a0[other[p]]),tot0-=a0[other[p]];
for (LL p=last[x];p;p=pre[p])
if (other[p]!=father[x]) ansx+=*a1[other[p]]*(tot1-a1[other[p]]),tot1-=a1[other[p]];
for (LL p=last[x];p;p=pre[p])
if(other[p]!=father[x]) a1[x]+=a0[other[p]],a0[x]+=a1[other[p]];
} else {
LL tot0=,tot1=;
for (LL p=last[x];p;p=pre[p])
if (other[p]!=father[x]) tot0+=a0[other[p]],tot1+=a1[other[p]];
ansx+=*tot1;
for (LL p=last[x];p;p=pre[p])
if (other[p]!=father[x]) ansx+=*a1[other[p]]*(tot0-a0[other[p]]);
for (LL p=last[x];p;p=pre[p])
if (other[p]!=father[x]) a1[x]+=a1[other[p]],a0[x]+=a0[other[p]];
}
//printf("%d %d\n",x,ansor);
//printf("%d %d\n",x,ansx);
} int main() {
freopen("tree.in","r",stdin); freopen("tree.out","w",stdout);
LL task,x,y; scanf("%lld",&task);
while (task--) {
memset(last,,sizeof last);
memset(flag,,sizeof flag); l=;
ANS=ANSor=ANSx=;
scanf("%lld",&n);
for (LL i=;i<=n;i++) scanf("%lld",&key[i]);
for (LL i=;i<n;i++) {
scanf("%lld%lld",&x,&y);
connect(x,y); connect(y,x);
}
//printf("fuck\n");
LL h=,t=;
que[]=; flag[]=;
while (h<t) {
LL cur=que[++h];
flag[cur]=;
for (LL p=last[cur];p;p=pre[p]) {
if (flag[other[p]]) continue;
que[++t]=other[p];
father[other[p]]=cur;
}
}
//for (LL i=1;i<=n;i++) printf("%d ",que[i]);
LL cur=;
for (LL i=;i<=;i++) {
for (LL j=;j<=n;j++) color[j]=(key[j]&cur)?:;
ans=ansor=ansx=; //work(1,-1);
for (LL j=n;j;j--) update(que[j]);
for (LL j=;j<=n;j++) ans+=color[j]; //printf("%d\n",ansor);//printf("%d\n",ans);
ANS+=ans*cur;
ANSor+=ansor*cur;
ANSx+=ansx*cur;
//for (LL j=1;j<=n;j++) printf("%d %d %d\n",j,size[j],sum[j]); printf("\n");
//for (LL j=1;j<=n;j++) printf("%d %d %d\n",j,size[j],num[j]); printf("\n");
//for (LL j=1;j<=n;j++) printf("%d %d %d\n",j,a0[j],a1[j]); printf("\n");
cur<<=;
}
double ans1=double(ANS)/double(n*n);
double ans2=double(ANSor)/double(n*n);
double ans3=double(ANSx)/double(n*n);
printf("%.3f %.3f %.3f\n",ans1,ans2,ans3);
}
fclose(stdin); fclose(stdout);
return ;
}

【HNOI】 小A的树 tree-dp的更多相关文章

  1. 牛客挑战赛30 小G砍树 树形dp

    小G砍树 dfs两次, dp出每个点作为最后一个点的方案数. #include<bits/stdc++.h> #define LL long long #define fi first # ...

  2. 【BZOJ5072】[Lydsy十月月赛]小A的树 树形DP

    [BZOJ5072][Lydsy十月月赛]小A的树 题解:考虑我们从一个联通块中替换掉一个点,导致黑点数量的变化最多为1.所以我们考虑维护对于所有的x,y的最大值和最小值是多少.如果询问的y在最大值和 ...

  3. bzoj 5072 小A的树 —— 树形DP

    题目:https://www.lydsy.com/JudgeOnline/problem.php?id=5072 由于对于一个子树,固定有 j 个黑点,连通块大小是一个连续的范围: 所以记 f[i][ ...

  4. 小A的树 - 树形DP

    题面 1 9 4 4 1 1 5 1 2 3 2 3 6 6 7 6 8 9 6 0 1 0 1 0 0 1 0 1 3 2 7 3 4 0 9 5 YES YES NO NO 题解 n <= ...

  5. bzoj 5072 [Lydsy1710月赛]小A的树——树形dp

    题目:https://www.lydsy.com/JudgeOnline/problem.php?id=5072 发现对于每个子树,黑点个数确定时,连通块的大小取值范围一定是一段区间:所以考虑只最小化 ...

  6. BZOJ5072:[Lydsy1710月赛]小A的树(树形DP)

    Description BZOJ只是扔了个下载链接 Solution 设$f[x][i]$表示$x$点选中$i$个黑点的最小连通块. 设$g[x][i]$表示$x$点选中$i$个黑点的最大连通块. 转 ...

  7. 洛谷P4426 毒瘤 [HNOI/AHOI2018] 虚树+树上dp

    正解:虚树+树上dp 解题报告: 传送门! 首先解释一下题意趴,,,语文70pts选手已经开始看不懂题辣QAQ 大概就是个给一个图,求独立集方案,且保证图是联通的,边的数量最多只比点多10 首先思考如 ...

  8. 2018.07.08 hdu4521 小明系列问题——小明序列(线段树+简单dp)

    小明系列问题--小明序列 Time Limit: 3000/1000 MS (Java/Others) Memory Limit: 65535/32768 K (Java/Others) Proble ...

  9. HDU 5905 Black White Tree(树型DP)

    题目链接  Black White Tree 树型DP,设$f[i][j]$为以$i$为根的子树中大小为$j$的连通块中可以包含的最小黑点数目. $g[i][j]$为以$i$为根的子树中大小为$j$的 ...

  10. 【POJ 2486】 Apple Tree(树型dp)

    [POJ 2486] Apple Tree(树型dp) Time Limit: 1000MS   Memory Limit: 65536K Total Submissions: 8981   Acce ...

随机推荐

  1. OSG学习:位置变换节点示例

    osg::PositionAttitudeTransform节点. #include <osgViewer\Viewer> #include <osg\Node> #inclu ...

  2. Python实现XML的操作

    本文从以下两个方面, 用Python实现XML的操作: 一. minidom写入XML示例1 二. minidom写入XML示例2 三. ElementTree写入/修改示例 四. ElementTr ...

  3. dedecms给原模型添加新字段

    1.进入dedecms后台 2.点击核心=>频道模型=>内容模型管理(在这里可以看到dedecms预设的模型设置) 3.选中我们需要的模型,点击更改,跳入以下页面 4.点击字段管理(可以看 ...

  4. java数据结构-HashMap

    一直以来似乎都有一个错觉,认为map跟其他的集合类一样继承自Collection,其实不然,Map和Collection在结构层次上是没有任何关系的,通过查看源码可以发现map所有操作都是基于key- ...

  5. javabean 参数收集 设置属性 设置不同级别的域对象的属性 默认存储在pagecontext中

    javabean 参数收集  设置属性 设置不同级别的域对象的属性  默认存储在pagecontext中

  6. bzoj1143-祭祀

    题目 给出一个有向无环图,要在上面安放祭祀点.两个祭祀点必须不可达,求最多能安放多少个祭祀点. 分析 由于一条无法再延伸链上只能安放一个祭祀点,而我们要求的是最多能安放祭祀点的个数,所以要求的就是最长 ...

  7. [洛谷P5068][Ynoi2015]我回来了

    题目大意:给你一张$n(n\leqslant10^3)$个点$m(m\leqslant10^5)$个点的无向无权图,多组询问,每次询问给你一些二元组$(x_i,y_i)$,求有多少个$u$于至少一个二 ...

  8. 一条数据的HBase之旅,简明HBase入门教程-Write全流程

    如果将上篇内容理解为一个冗长的"铺垫",那么,从本文开始,剧情才开始正式展开.本文基于提供的样例数据,介绍了写数据的接口,RowKey定义,数据在客户端的组装,数据路由,打包分发, ...

  9. Linux(ubuntu 12.04桌面版) 搭建Android开发环境

    因为一些工作上的原因,需要切换到Linux环境下做点开发,我选择的Linux发行版本为ubuntu(我不建议使用fedora,我最开始就是使用的fedora,但发现并不是特别好使,有些插件没办法安装, ...

  10. [zhuan]Android程序的真正入口Application

    http://blog.csdn.net/coding_or_coded/article/details/6602560 接触android已经有一段时间了,一直以为android程序的入口是配置文件 ...