字符串训练之三

字符串训练三

https://www.luogu.org/problem/P4551

题目描述:

给定一棵n个点的带权树,结点下标从1开始到N。寻找树中找两个结点,求最长的异或路径。

异或路径指的是指两个结点之间唯一路径上的所有边权的异或

分析:

嗯?这不是个图论题吗?什么狗屁字符串?

首先看到异或,那01trie树就必不可少的了

首先对一条边异或2次,相当于没有异或。

这样的话 i -> j 的异或和,就是 i -> 1 的异或和,再异或上 1 -> j 的异或和。

处理出每个点到1路径的异或和,然后找两个,使它们异或起来最大。

等等这不又是板子题吗?

找出两个异或最大(这个我前面两个练习有说)

于是直接套板子即可

code by wzxbeliever

#include<bits/stdc++.h>
#define ll long long
#define ri register int
#define il inline
#define lowbit(x) x&(-x)
using namespace std;
const int maxn=100005;
int head[maxn],tr[maxn*31][2],w[maxn]; 
int n,ans,rt,cnt,tot;
struct node{int to,next,w;}edg[maxn<<1];
il void add(int u,int v,int w){++cnt;edg[cnt].next=head[u];edg[cnt].w=w;edg[cnt].to=v;head[u]=cnt;}
il void bulid(int x,int rt){
     for(ri i=1<<30;i;i>>=1){bool c=x&i;
     if(!tr[rt][c])tr[rt][c]=++tot;
     rt=tr[rt][c];
     }
}
il int query(int x,int rt){
     int ans=0; 
     for(ri i=1<<30;i;i>>=1){bool c=x&i;
     if(tr[rt][c^1])ans+=i,rt=tr[rt][c^1];
     else rt=tr[rt][c];
     }return ans;
}
il void dfs(int u,int fa){
    for(ri i=head[u];i;i=edg[i].next){int to=edg[i].to;
    if(to==fa)continue;
    w[to]=w[u]^edg[i].w;dfs(to,u);
    }
}
int main()
{
//  freopen(".in","r",stdin);
//  freopen(".out","w",stdout);
    scanf("%d",&n);
    for(ri i=1,u,v,w;i<n;i++)scanf("%d%d%d",&u,&v,&w),add(u,v,w),add(v,u,w);
    dfs(1,0);
    for(ri i=1;i<=n;i++)bulid(w[i],rt);
    for(ri i=1;i<=n;i++)ans=max(ans,query(w[i],rt));
    printf("%d\n",ans);
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/wzxbeliever/p/11621318.html