【HNOI】 小A的树 tree-dp

本文详细介绍了如何通过树形结构进行DP操作以求解特定路径上的and、or、xor值的期望问题。针对每个节点的状态定义及转移方程进行了深入探讨,并提供了完整的代码实现。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

  【题目描述】给定一颗树,每个点有各自的权值,任意选取两个点,要求算出这两个点路径上所有点的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<<1],other[maxn<<1],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]=1; num[x]=0; 
    if (color[x]) a1[x]=1,a0[x]=0; else a0[x]=1,a1[x]=0;
    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=0;
        for (LL p=last[x];p;p=pre[p]) if (other[p]!=father[x]) ans+=2*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+=2*num[other[p]]*(tot-size[other[p]]),num[x]+=num[other[p]],tot-=num[other[p]];
    }
    if (color[x]) {
        LL tot0=0,tot1=0;
        for (LL p=last[x];p;p=pre[p]) 
            if (other[p]!=father[x]) tot0+=a0[other[p]],tot1+=a1[other[p]];
        ansx+=2*tot0+1;
        for (LL p=last[x];p;p=pre[p]) 
            if (other[p]!=father[x]) ansx+=2*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+=2*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=0,tot1=0;
        for (LL p=last[x];p;p=pre[p])
            if (other[p]!=father[x]) tot0+=a0[other[p]],tot1+=a1[other[p]];
        ansx+=2*tot1;
        for (LL p=last[x];p;p=pre[p])
            if (other[p]!=father[x]) ansx+=2*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,0,sizeof last); 
        memset(flag,0,sizeof flag); l=0;
        ANS=ANSor=ANSx=0;
        scanf("%lld",&n);
        for (LL i=1;i<=n;i++) scanf("%lld",&key[i]);
        for (LL i=1;i<n;i++) {
            scanf("%lld%lld",&x,&y); 
            connect(x,y); connect(y,x);    
        }
        //printf("fuck\n");    
        LL h=0,t=1;
        que[1]=1; flag[1]=1;
        while (h<t) {
            LL cur=que[++h];
            flag[cur]=1;
            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=1;
        for (LL i=1;i<=20;i++) {
            for (LL j=1;j<=n;j++) color[j]=(key[j]&cur)?1:0;
            ans=ansor=ansx=0; //work(1,-1);
            for (LL j=n;j;j--) update(que[j]);
            for (LL j=1;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<<=1;
        }
        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 0;
}

 

转载于:https://www.cnblogs.com/BLADEVIL/p/3626268.html

资源下载链接为: https://pan.quark.cn/s/9648a1f24758 这个HTML文件是一个专门设计的网页,适合在告白或纪念日这样的特殊时刻送给女朋友,给她带来惊喜。它通过HTML技术,将普通文字转化为富有情感和创意的表达方式,让数字媒体也能传递深情。HTML(HyperText Markup Language)是构建网页的基础语言,通过标签描述网页结构和内容,让浏览器正确展示页面。在这个特效网页中,开发者可能使用了HTML5的新特性,比如音频、视频、Canvas画布或WebGL图形,来提升视觉效果和交互体验。 原本这个文件可能是基于ASP.NET技术构建的,其扩展名是“.aspx”。ASP.NET是微软开发的一个服务器端Web应用程序框架,支持多种编程语言(如C#或VB.NET)来编写动态网页。但为了在本地直接运行,不依赖服务器,开发者将其转换为纯静态的HTML格式,只需浏览器即可打开查看。 在使用这个HTML特效页时,建议使用Internet Explorer(IE)浏览器,因为一些老的或特定的网页特效可能只在IE上表现正常,尤其是那些依赖ActiveX控件或IE特有功能的页面。不过,由于IE逐渐被淘汰,现代网页可能不再对其进行优化,因此在其他现代浏览器上运行可能会出现问题。 压缩包内的文件“yangyisen0713-7561403-biaobai(html版本)_1598430618”是经过压缩的HTML文件,可能包含图片、CSS样式表和JavaScript脚本等资源。用户需要先解压,然后在浏览器中打开HTML文件,就能看到预设的告白或纪念日特效。 这个项目展示了HTML作为动态和互动内容载体的强大能力,也提醒我们,尽管技术在进步,但有时复古的方式(如使用IE浏览器)仍能唤起怀旧之情。在准备类似的个性化礼物时,掌握基本的HTML和网页制作技巧非常
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值