UVA 13277(UVALive 8083) XOR Path

题目链接:https://cn.vjudge.net/problem/UVA-13277https://cn.vjudge.net/problem/UVALive-8083

Time limit 1000 ms(UVA),3000 ms(UVALive)

You are given an unrooted weighted tree. The weights on the edges


are 16 bit unsigned integers, that is they are between 0 to 2^16 - 1 (inclusive). For every integer x in the range 0 to 2^16 - 1 (inclusive) find out how many pairs (unordered) of distinct nodes in the given tree have distance x . Distance between two nodes in the tree is defined as the bitwise xor of the edge weights on the path between these two nodes.
For example consider the tree on the right: There are four nodes A , B , C and D in this tree. The edge weights are: AB (5) , AC (2) and AD (1) . So the distance between A and D is 1, B and C is 7 , B and D is 4 etc.
Input
First line of the input contains a positive integer T (T ≤ 10) denoting the number of test cases. Hence T cases follow. Each case starts with a positive integer n (n ≤ 100000) denoting the number of nodes in the tree. Hence n - 1 lines follow with the format ‘u v w’ meaning there is an edge between u and v (1 ≤ u; v ≤ n) with the weight w .
Output
For each test case output the case number (no trailing space after ‘Case x:’ ) followed by the number of paths with the distance x for every x in the range 0 to 2^16 - 1 (inclusive). There should NOT be empty line(s) between two cases. Please see the Sample Input output for the details.
Note for the Sample: Please note, the output below is truncated intentionally to save the trees, electricity, ram consumption, network bandwidth and so on. In fact, till 2^16 - 9, ‘ 0’s follow.
Sample Input

1
4
1 2 5
1 3 2
1 4 1
Sample Output
Case 1:
0

1

1

1

1

1

0

1

0

题意:

给你一棵树求出任意一条路径的边权异或和分别为0到2^16-1的个数。

思路:

我先讲一下怎么做,对树进行一遍dfs求出对于随便找的一个根(我找的是0节点,也就是题目中所描述的1节点)到其他所有点的路径异或和,用一个桶记录异或和的路径条数。对这个桶进行FWT,自己和自己卷积后再UFWT回去,不过其中会有重复的数量,对于异或和等于0需要减去n-1,求出来的路径条数是对于(u,v)和(v,u)是不同方案的,需要对每个值的数量除于二。再加上之前根节点到其他节点的路径异或和条数。

输出答案就做完了,下面我就简要说一下为什么要怎么做?

首先我们先dfs求出根节点到其他节点的异或和数量,如果我们对(root,u)的路径异或和异或上(root,v)的路径异或和,那么对于(root,lca(u,v))这条路径的异或和因为异或的性质而被抵消了。因为懒我就不画图举栗子了,读者可以手动构造一棵树去看一下。

对于每一个异或和值的数量可以写为c[k]=\sum_{i\bigoplus j=k}a[i]\times b[j]

这不就是FWT能加速的公式吗,直接上FWT即可,再按照之前所讲的去个重即可。需要注意卷积出来的值不包含从根节点到其他节点路径异或和条数,需要单独加。

示例程序

#include <bits/stdc++.h>
#define LDQ 1000000007
#define QAQ 0x3f3f3f3f
#define INF 1000000000000000000
#define PI 3.14159265358979323846
#define inv2 ((LDQ+1)>>1)
using namespace std;
struct jj
{
    int v,next,c;
}w[200000];
int h[100000],numw;
long long ans[100000],temp[100000];
void insert(int u,int v,int c)
{
    w[numw].v=v;
    w[numw].c=c;
    w[numw].next=h[u];
    h[u]=numw++;
}
void FWT(long long x1[],int n)
{
    int i,j,d,m;
    long long x,y;
    for(d=1;n>d;d<<=1)
    {
        for(m=d<<1,i=0;n>i;i+=m)
        {
            for(j=0;d>j;j++)
            {
                x=x1[i+j];
                y=x1[i+j+d];
                x1[i+j]=x+y;
                x1[i+j+d]=x-y;
            }
        }
    }
}
void UFWT(long long x1[],int n)
{
    int d,m,i,j;
    long long x,y;
    for(d=1;n>d;d<<=1)
    {
        for(m=d<<1,i=0;n>i;i+=m)
        {
            for(j=0;d>j;j++)
            {
                x=x1[i+j];
                y=x1[i+j+d];
                x1[i+j]=(x+y)/2;
                x1[i+j+d]=(x-y)/2;
            }
        }
    }
}
void Convolution(long long x1[],int len)
{
    int i;
    FWT(x1,len);
    for(i=0;len>i;i++)
    {
        x1[i]=x1[i]*x1[i];
    }
    UFWT(x1,len);
}
void dfs(int pos,int fa,int num)
{
    int i;
    for(i=h[pos];i!=-1;i=w[i].next)
    {
        if(fa!=w[i].v)
        {
            ans[num^w[i].c]++;
            dfs(w[i].v,pos,num^w[i].c);
        }
    }
}
int main()
{
    int t,n,u,v,c,i,ca=1;
    scanf("%d",&t);
    while(t--)
    {
        scanf("%d",&n);
        memset(h,-1,sizeof(h));
        memset(ans,0,sizeof(ans));
        numw=0;
        for(i=1;n>i;i++)
        {
            scanf("%d %d %d",&u,&v,&c);
            insert(u-1,v-1,c);
            insert(v-1,u-1,c);
        }
        dfs(0,-1,0);						//跑dfs求出根节点到其他节点的异或和数量
        memcpy(temp,ans,sizeof(temp));		//卷积后不包含根节点到其他节点的路径异或和条数,这些路径异或和条数需要取出来
        Convolution(ans,1<<16);
        ans[0]=ans[0]-n+1;
        printf("Case %d:\n",ca++);
        for(i=0;(1<<16)>i;i++)
        {
            printf("%lld\n",ans[i]/2+temp[i]);
        }
    }
    return 0;
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值