【poj3764】 The xor-longest Path

[http://poj.org/problem?id=3764] (题目链接)

今天的考试题,看到异或就有点虚,根本没往正解上想。。

题意:给出一棵带权树,请找出树上的一条路径,使其边上权值的异或和最大。

solution 
  首先我们考虑从根向下dfs,记录下每个点i到根上权值的异或和val[i]。根据异或和的性质:x^y^y=x。所以我们可以由val[]数组两两组合得出树上任意两点之间路径的异或和。(不理解请自己脑补OvO) 
  然而这样对于时间复杂度并没有提高,仍然需要枚举两点。所以我们考虑从异或这个运算的本质下手。要使两个数的异或和尽可能大,那么这两个数的二进制高位的数就要尽可能不同。其实这是贪心思想,对于每一个val[i],我们把它拆成二进制数,由高位向低位,尽可能使当前位上的数与val[i]当前位上的数不同(这样对答案的贡献最大)。 
  对于这样一个算法,我们可以用trie树维护。根据深度建树30层,每一个节点的儿子就是0和1,表示有没有一个val[i]在这一位存在0或1。这样就很好的解决了问题。复杂度O(n*30)。

代码:

// poj3764
#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdlib>
#include<cstdio>
#include<cmath>
#define MOD 1000000007
#define inf 2147483640
#define LL long long
#define free(a) freopen(a".in","r",stdin);freopen(a".out","w",stdout);
using namespace std;

const int maxn=100010;
struct edge {int to,next,w;}e[maxn<<1];

int vis[maxn],val[maxn],m[maxn],tr[maxn<<4][2],head[maxn],cnt,n;

void dfs(int u,int w) {
    vis[u]=1;
    for (int i=head[u];i;i=e[i].next) if (!vis[e[i].to])
            dfs(e[i].to,w^e[i].w);
    val[u]=w;
}
void insert(int x) {
    int u=0;
    for (int i=30;i>=0;i--) {
        int k=x&m[i];k>>=i;
        if (!tr[u][k]) tr[u][k]=++cnt;
        u=tr[u][k];
    }
}
int main() {
    m[0]=1;
    for (int i=1;i<=30;i++) m[i]=2*m[i-1];
    while (scanf("%d",&n)!=EOF) {
        cnt=0;
        memset(vis,0,sizeof(vis));memset(head,0,sizeof(head));
        memset(tr,0,sizeof(tr));
        for (int i=1;i<n;i++) {
            int x,y,w;
            scanf("%d%d%d",&x,&y,&w);
            x++,y++; //因为节点编号是从0开始,所以全部+1
            e[i].to=y;e[i].w=w;e[i].next=head[x];head[x]=i;
            e[i+n].to=x;e[i+n].w=w;e[i+n].next=head[y];head[y]=i+n;
        }
        dfs(1,0);
        for (int i=1;i<=n;i++) insert(val[i]);
        int ans=0;
        for (int i=0;i<=n;i++) {
            int u=0,x=val[i],s=0;
            for (int j=30;j>=0;j--) {
                int k=x&m[j];k>>=j;
                if (tr[u][k^1]) s+=m[j],u=tr[u][k^1];
                else u=tr[u][k];
            }
            ans=max(ans,s);
        }
        printf("%d\n",ans);
    }
    return 0;
}

  

时间: 2024-10-11 09:54:30

【poj3764】 The xor-longest Path的相关文章

【Math】GCD XOR 证明

题目:Given an integer N, and how many pairs (A;B) are there such that: gcd(A;B) = A xor B where 1<=B<=A<=N. 首先先爆一发,妥妥超时.其实真相是我想打表找规律.结果没什么规律可循. 后来分析:要想让GCD(A,B)==(A^B),A和B一定是同样的位数(二进制).因此打表方法可变为:(亦超时) void init() { int K=0; int last=0; for(int i=1;

【BZOJ2337】[HNOI2011]XOR和路径 期望DP+高斯消元

[BZOJ2337][HNOI2011]XOR和路径 Description 题解:异或的期望不好搞?我们考虑按位拆分一下. 我们设f[i]表示到达i后,还要走过的路径在当前位上的异或值得期望是多少(妈呀好啰嗦),设d[i]表示i的度数.然后对于某条边(a,b),如果它的权值是1,那么f[b]+=(1-f[a])/d[a]:如果它的权值是0,那么f[b]+=f[a]/d[a],然后我们移个项,就变成了一堆方程组求解,直接高斯消元. 别忘了f[n]=0! #include <cstdio> #i

【BZOJ4269】再见Xor 高斯消元

[BZOJ4269]再见Xor Description 给定N个数,你可以在这些数中任意选一些数出来,每个数可以选任意多次,试求出你能选出的数的异或和的最大值和严格次大值. Input 第一行一个正整数N. 接下来一行N个非负整数. Output 一行,包含两个数,最大值和次大值. Sample Input 3 3 5 6 Sample Output 6 5 HINT 100% : N <= 100000, 保证N个数不全是0,而且在int范围内 题解:大水~ 在线性基上贪心得到最大值,用最大值

【HackerRank】Maximizing XOR

给定两个整数:L 和 R ∀ L ≤ A ≤ B ≤ R, 找出 A xor B 的最大值. 输入格式 第一行包含 L 第一行包含 R 数据范围 1 ≤ L ≤ R ≤ 103 输出格式 输出最大的异或和 题解: 1 import java.io.*; 2 import java.util.*; 3 import java.text.*; 4 import java.math.*; 5 import java.util.regex.*; 6 7 public class Solution { 8

【UVA】12716-GCD XOR

做出做道题需要注意2个地方: 首先可以打表找规律,找到规律我们可以发现: 1.如果gcd(a,b) = a ^ b = c,那么 b = a - c; 既然这样我们可以枚举a,c,求出b之后判断 c 是否等于 a ^ b,那么如何枚举c呢? 2.利用类似筛选素数的方法去枚举a,c 首先c是a的约数,所以这道题我们需要枚举的其实是a的约数,但是约数也不好枚举,我们可以通过c去枚举a,我们通过枚举c,找到约数是c的所有a. 这题由于数据过大,需要打表,否则超时. 14024658 12716 GCD

【POJ3764】The xor-longest Path Trie树+异或性质

#include <stdio.h> int main() { puts("转载请注明出处[vmurder]谢谢"); puts("网址:blog.csdn.net/vmurder/article/details/43486733"); } 题意: 多组数据. 给你一颗树, 然后求一条最长异或路径, 异或路径长度定义为两点间简单路径上所有边权的异或和. 题解: 首先无根树转有根树再在树上跑一遍算出每个点到根的异或和. 然后两点间异或路径长度就是a[i]*

【LeetCode】Binary Tree Maximum Path Sum 解题报告

[题目] Given a binary tree, find the maximum path sum. The path may start and end at any node in the tree. For example: Given the below binary tree, 1 / 2 3 Return 6. [解析] 题意:在二叉树中找一条路径,使得该路径的和最大.该路径可以从二叉树任何结点开始,也可以到任何结点结束. 思路:递归求一条经过root的最大路径,这条路径可能是:

【Trie】The XOR Largest Pair

[题目链接] https://loj.ac/problem/10050 [题意] 给出n个数,其中取出两个数来,让其异或值最大. [题解] 经典的01字典树问题. 首先需要把01字典树建出来. 然后对于每一个串都跑一遍.如果存在当前位 不同的 节点,就往那里跑,否则顺着跑. 一切尽在代码中. [代码] 1 #include<bits/stdc++.h> 2 using namespace std; 3 typedef long long ll; 4 const int N = 1e5+10;

poj3764 The XOR Longest Path【dfs】【Trie树】

The xor-longest Path Time Limit: 2000MS   Memory Limit: 65536K Total Submissions: 10038   Accepted: 2040 Description In an edge-weighted tree, the xor-length of a path p is defined as the xor sum of the weights of edges on p: ⊕ is the xor operator. W