POJ 3764 The xor-longest Path ( 字典树应用—— 求连续段相异或最大最小的线性算法)(好题)

题意:已知:给出n个结点的树,定义:两结点间的权值为两点之间所有边相异或的值.求:树中的某两点间的最大权值.

思路:先说简单一点的题:有道CowXor,是一串线性序列,求某连续段异或的最大值,这题的思路是先求前i项序列相异或的值Si,所以x到y的连续异或就是Sx^Sy ,因为a^b = (a ^ c) ^ (b ^ c).

这题同样是这个思路把线性拓展到树上,先求任何点到某一定点的连续异或值,比如选根结点0,所以这时候有两种情况,1.x,y的路径通过了根结点,显然正确。2.x,y的路径不通过根结点,可以知道a^b = (a ^ c) ^ (b ^ c). c就是他们到根结点的共同的路径,同样也正确。

这是第一大步,第二,求出以后不能直接暴力枚举所有两点,n^2 的复杂度会T,可以用字典树把复杂度降到几乎线性

第一大步已经求出了Si,再从i=1 to n,再字典树上插入Si,再求出当前情况下,路径权的最大值,也就是从根结点往下走,有与当前位相异的值就累加,这点自己想一下即可。

代码:

//15560K	735MS
#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cstring>
using namespace std;
const int N= 1e5+100;
int n,ans;
struct edge{
    int to;
    int next;
    int w;
}es[N<<1];
bool vis[N];
int head[N];
inline void add_edge(int u,int v,int w,int i){
    es[i].to=v;
    es[i].w=w;
    es[i].next=head[u];
    head[u]=i;
}

int XOR[N];
void dfs(int u){
    vis[u]=1;
    for(int k=head[u];k!=-1;k=es[k].next){
        if(vis[es[k].to]) continue;
        else XOR[es[k].to]=XOR[u]^es[k].w;
        dfs(es[k].to);
    }
}
struct Trie{
    int child[2];
    void ini(){
        child[0]=0;
        child[1]=0;
    }
}trie[N<<8];
int L;

void Insert(int val){
    int cur=0;
    for(int i=30;i>=0;i--){

        int m=val&(1<<i)? 1:0;
        if(!trie[cur].child[m]){
            trie[cur].child[m]=++L;
            trie[L].ini();
        }
        cur=trie[cur].child[m];

    }
}
int Find(int val){
    int ans=0;
    int cur=0;
    for(int i=30;i>=0;i--){
        int g=val&(1<<i)? 0:1;
        if(trie[cur].child[g]){
            ans|=1<<i;
            cur=trie[cur].child[g];
        }
        else {
            cur=trie[cur].child[!g];
        }
    }
    return ans;
}
void ini(){
    memset(head,-1,sizeof(head));
    memset(vis,0,sizeof(vis));
    ans=-1;
    trie[0].ini();
    L=0;
}

int main(){
    while(~scanf("%d",&n)){
        ini();
        for(int i=1;i<=n-1;i++){
            int u,v,w;
            scanf("%d%d%d",&u,&v,&w);
            add_edge(u,v,w,i);
            add_edge(v,u,w,i+n-1);
        }
        dfs(0);
        for(int u=0;u<n;u++){
            Insert(XOR[u]);
            int t=Find(XOR[u]);
            ans=max(ans,t);
        }
        printf("%d\n",ans);
    }
    return 0;
}

开始用动态分配字典树空间T了,然后用了静态wa了....我误认为数据中0就是根结点,1...n依次根据深度编号..但是1...n不是根据深度编号的也就是随便编号的...

比如2结点可能连在10结点上,10结点却连在0号根结点上

所以由原来的添边add_edge(min(v,u),max(v,u),w,i);

改成了add_edge(u,v,w,i);  add_edge(v,u,w,i+n-1);双向边,就ac了

时间: 2024-10-13 22:44:49

POJ 3764 The xor-longest Path ( 字典树应用—— 求连续段相异或最大最小的线性算法)(好题)的相关文章

POJ - Colored Sticks - 并查集+字典树

这道题主要还是要判断是不是欧拉图 说白了就是能不能这幅图能不能用一笔画下来,那么就可以知道了,如果是一个环状的,说明奇数度就不存在,否则就只能用两个奇数度(起点终点)//我的理解这是 只需要用字典树将单词变为对应的一个数字,然后并查集操作就可以,需要维护一个度变量 #include<stdio.h> #include<string.h> int du[500010],p[500010]; int tot=1; struct tree { tree *next[30]; int id

poj 3764 The xor-longest Path(字典树)

题目链接:poj 3764 The xor-longest Path 题目大意:给定一棵树,每条边上有一个权值,找出一条路径,使得路径上权值的亦或和最大. 解题思路:dfs一遍,预处理出每个节点到根节点路径的亦或和rec,那么任意路径均可以表示rec[a] ^ rec[b],所以问题 就转换成在一些数中选出两个数亦或和最大,那么就建立字典树查询即可. #include <cstdio> #include <cstring> #include <algorithm> us

POJ 3764 The xor-longest Path 字典树求最大异或

题意,一颗树,每个边有个值,在树上找一条简单路径,使得这条路径上的边权异或值最大 把这题模型转换一下, 对于任意一条路径的异或,表示为f(u, v) 则f(u, v) = f(1, u) ^ f(1, v) 这是显然的 其中f(1, i)是可以再O(n)内处理出来 然后就是在一个数组内,找两个数异或值最大 然后就可以用字典树来搞 每个数变成01串,  然后插入字典树, 第30位在最前,然后29,依次到0位 就建立成了一个深度为31的字典树 对于一个询问,在字典树上找,就是尽量找跟其相反的路径.

POJ 3764 The xor-longest Path ( 字典树求异或最值 &amp;&amp; 异或自反性质 &amp;&amp; 好题好思想)

题意 : 给出一颗无向边构成是树,每一条边都有一个边权,叫你选出一条路,使得此路所有的边的异或值最大. 分析 : 暴力是不可能暴力的,这辈子不可能暴力,那么来冷静分析一下如何去做.假设现在答案的异或值的最大的路的起点和终点分别为 a.b,这个异或值为了方便我用 ⊕(a, b) 表示,那么接下来有一个巧妙的转化 ⊕(a, b) == ⊕(root, a) ^ ⊕(root, b) ,这个转化在 LCA(a, b) == root 的时候明显成立,因为重复的部分会异或两次,相当于没有异或,而LCA(

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

Codeforces Round #482 (Div. 2)D. Kuro and GCD and XOR and SUM+字典树

题目链接:D. Kuro and GCD and XOR and SUM 题意:两种操作:第一种给数组添加一个数,第二种输入x,k,s,要求从数组中找到一个数v,要求k能整除gcd(k,v);并且v<=s-x,然后异或v与k的异或值最大. 题解:对与k大于1的情况我们暴力枚举过去,k为1的特殊处理建一颗字典树,如果可以的满足条件的话,每次取值时往相反方向取. 1 #include<bits/stdc++.h> 2 #include <iostream> 3 #include

HDU5715 XOR 游戏 二分+字典树+dp

当时Astar复赛的时候只做出1题,赛后补题(很长时间后才补,懒真是要命),发现这是第二简单的 分析: 这个题,可以每次二分区间的最小异或和 进行check的时候用dp进行判断,dp[i][j]代表前i个元素分成j个区间,j是最后一个区间的最后一个元素 如果dp[i][j]为真,表明每个区间长度大于L,异或和大于mid 否则为假 返回dp[n][m]就好 复杂度度 O(30^2*nm) 吐槽:和异或相关的题总是和字典树贪心有关,又是一道,铭记铭记 #include <stdio.h> #inc

POJ 1251 统计难题(初学字典树)

今天就这题照着别人的代码学了字典树... 这篇论文:http://wenku.baidu.com/view/d2ba836fb84ae45c3b358ca8.html介绍了各种字典树的运用,长了好多姿势,很有启发性 归纳一下字典树的应用: 检索(主要功能) 串排序 在DP中减少无效的状态转移 最长公共前缀问题(LCP)转化成LCA tire+KMP 构成AC自动机数据结构 Problem Description Ignatius最近遇到一个难题,老师交给他很多单词(只有小写字母组成,不会有重复的

poj 2513 Colored Sticks 欧拉回路(字典树 +并查集)

此题中涉及三个小算法,这是一个无向图判断欧拉回路, 无向图存在欧拉回路的充要条件 一个无向图存在欧拉回路,当且仅当该图只存在0或2个奇数度数的顶点,且该图是连通图. 有向图存在欧拉回路的充要条件 一个有向图存在欧拉回路,所有顶点的入度等于出度且该图是连通图. 判断度数很简单,当时没想明白怎么判断图示连通的,其实只要判断他们的父节点的个数,只要只有一个父节点,那么此图是连通的. 字典树分配一下他们的id就好了,还有卡住的一点就是零图是欧拉图. 还有我做了一个小小的剪芝,但是没有什么效果,只减少了3