• P4551 最长异或路径 (01字典树,异或前缀和)


    题目描述

    给定一棵 n 个点的带权树,结点下标从 1 开始到 N 。寻找树中找两个结点,求最长的异或路径。
    异或路径指的是指两个结点之间唯一路径上的所有边权的异或。

    输入输出格式

    输入格式:
    第一行一个整数 N ,表示点数。
    接下来 n-1n−1 行,给出 u,v,w ,分别表示树上的 u 点和 v 点有连边,边的权值是 w 。


    输出格式:
    一行,一个整数表示答案。

    输入输出样例

    输入样例#1:

    4
    1 2 3
    2 3 4
    2 4 6

    输出样例#1:

    7

    说明

    最长异或序列是1-2-3,答案是 7 (=3 ⊕ 4)

    数据范围

    1≤n≤100000; 0<u,v≤n; 0≤w<2^31

    Solution

    这道题,套路题啊...
    首先要考虑到两个思路:
    1.异或的基本性质:

    [{({x}igoplus{y})}igoplus{y}=x ]

    2.带修改的01字典树

    考虑枚举每一个点对,但是数据范围太大。
    此时我们可以使用01字典树,步骤如下:

    • 先将边权转化为点权,预先处理出从根节点到每一个点的异或前缀和。
    • 然后将所有点的异或前缀和插入字典树中。
    • 再进行查询,注意查询时要将查询的点暂时删除。
    • 查询最大值即为答案。

    代码

    #include<bits/stdc++.h>
    #define ll long long
    using namespace std;
    const int maxn=200008;        
    int ch[32*maxn][2];
    ll val[32*maxn],c[maxn];
    int num[32*maxn];
    int sz,n;
    ll b[maxn];
    
    void insert(ll a)
    {
        int u=0;
        for(int i=32;i>=0;i--)
        {
            int c=((a>>i)&1);
            if(!ch[u][c])
            {
                memset(ch[sz],0,sizeof(ch[sz]));
                val[sz]=0;
                num[sz]=0;
                ch[u][c]=sz++;
            }
            u=ch[u][c];
            num[u]++;
        }
        val[u]=a;
    }
    
    void update(ll a,int d)
    {
        int u=0;
        for(int i=32;i>=0;i--)
        {
            int c=((a>>i)&1);
            u=ch[u][c];
            num[u]+=d;
        }
    }
    
    ll query(ll x)
    {
        int u=0;
        for(int i=32;i>=0;i--)
        {
            int c=((x>>i)&1);
            if(ch[u][c^1]&&num[ch[u][c^1]]) 
            u=ch[u][c^1];
            else u=ch[u][c];
        }
        return x^val[u];
    }
    
    struct sj{
        int to;
        int next;
        int w;
    }a[maxn];
    int size,head[maxn];
    
    void add(int x,int y,int z)
    {
        a[++size].to=y;
        a[size].w=z;
        a[size].next=head[x];
        head[x]=size;
    }
    
    int v[maxn],now,ans=-1;
    void dfs(int x)
    {
        v[x]=1;
        c[x]=now;
        for(int i=head[x];i;i=a[i].next)
        {
            int tt=a[i].to;
            if(!v[tt])
            {
                now^=a[i].w;
                dfs(tt);
                now^=a[i].w;
            }
        }
    }
    
    int main()
    {
        cin>>n;
        for(int i=1;i<n;i++)
        {
            int x,y,z;
            scanf("%d%d%d",&x,&y,&z);
            add(x,y,z); add(y,x,z);
        }
        dfs(1);
        for(int i=1;i<=n;i++)
        insert(c[i]);
        for(int i=1;i<=n;i++)
        {
            update(c[i],-1);
            int kk=query(c[i]);
            ans=max(ans,kk);
            update(c[i],1);
        }	
        cout<<ans<<endl;
    } 
    
  • 相关阅读:
    蒲公英
    大神-YY
    iOS开发精选知识点讲解 - 视频等 iOSStrongDemo是由@李刚维护,总结一些iOS开发精选知识点。每一个知识点都有相应的测试代码,非常适合iOS初学者。
    iOS开发UI篇—懒加载
    iOS开发UI篇—UITableviewcell的性能优化和缓存机制
    iOS开发UI篇—UITableview控件基本使用
    iOS开发UI篇—UITableview控件简单介绍
    iOS — Autolayout之Masonry解读
    iOS开发UI篇—多控制器和导航控制器简单介绍
    iOS开发网络篇—数据缓存
  • 原文地址:https://www.cnblogs.com/Kv-Stalin/p/9240958.html
Copyright © 2020-2023  润新知