zoukankan      html  css  js  c++  java
  • POJ 3764 The xor-longest Path (01字典树)

    <题目链接>

    题目大意:

    给定一颗$n$个节点$(nleq10^5)$,有边权的树,其边权$(0leq w < 2^{31})$。让你求出这棵树上任意两个节点之间的异或最大值。

    解题分析:

    先用DFS预处理出根节点到所有节点的路径异或值,然后任意两点$u,v$之间的路径异或值就能通过 $(u->rt) xor (v->rt)$的异或值得到,因为根节点到u、v的最近公共祖先的路径被异或了两次,所以能够直接得到u,v之间的异或距离。但是因为节点数量有$10^5$个,直接枚举两两节点肯定超时。用01字典树优化一下,快速找到异或的最大值。

    #include <cstdio>
    #include <cstring>
    #include <algorithm>
    #include <iostream>
    using namespace std;
    
    typedef long long ll;
    
    template<typename T>
    inline void read(T&x){     
      x=0;int f=1;char ch=getchar();
      while(ch<'0' ||ch>'9'){ if(ch=='-')f=-1; ch=getchar(); }
      while(ch>='0' && ch<='9'){ x=x*10+ch-'0'; ch=getchar(); }
      x*=f;
    }
    
    #define rep(i,s,t) for(int i=s;i<=t;i++)
    #define clr(a,b) memset(a,b,sizeof(a))
    const int N = 1e5+5;
    ll nxt[N*32][2],xoval[N];
    int n,rt;
    
    struct Edge{int to,nxt;ll w; }e[N<<1];
    int head[N],cnt,pos;
    
    inline void init(){
      cnt=0;clr(head,-1);
      pos=1;clr(nxt,0);clr(xoval,0);
    }
    inline void add(int u,int v,int w){
      e[cnt]=(Edge){v,head[u],w};head[u]=cnt++;
    }
    void dfs(int u,int pre,ll nowval){     //得到根到所有点的异或值
      xoval[u]=nowval;
      for(int i=head[u];~i;i=e[i].nxt){
        int v=e[i].to;
        if(v==pre)continue;
        dfs(v,u,nowval^e[i].w);
      }
    }
    inline void Insert(ll x){
      int now=1;
      for(int i=30;i>=0;i--){
        int to=(x>>i)&1;
        if(!nxt[now][to])nxt[now][to]=++pos;
        now=nxt[now][to];
        //num[now]++;
      }
    }
    /*inline void del(ll x){      //将01字典树中删除x
        int now=1;
        for(int i=30;i>=0;i--){
            int to=(x>>i)&1;
            num[now]--;
            now=nxt[now][to];
        }
    }*/
    inline ll query(ll x){
      int now=1;ll ans=0;
      for(int i=30;i>=0;i--){
        int to=(x>>i)&1;
        if(nxt[now][to^1])now=nxt[now][to^1],ans+=(1<<i);
        else now=nxt[now][to];
      }
      return ans;
    }
    int main(){
      while(~scanf("%d",&n)){
        init();
        rep(i,1,n-1){      
            int u,v;ll w;read(u);read(v);read(w);
            add(u,v,w);add(v,u,w);     
        }
        dfs(0,-1,0); 
        ll ans=-1e18;
        rep(i,0,n-1){
            ll res=query(xoval[i]);
            ans=max(ans,res);
            Insert(xoval[i]);
        }
        printf("%lld
    ",ans);
      }
    }
  • 相关阅读:
    打印对象的 “精心骗局”
    js继承(自备水,这非常干货)
    递归实现深拷贝( 只要学过js递归,看不懂找我包会 )
    PuTTY SSH 使用证书免密码登录
    git 使用
    php socket通信的简单实现
    基于PHP实现短信验证码接口的方法
    PHP实现页面静态化的简单方法分享
    Yii2使用数据库操作汇总(增删查改、事务)
    PHP 获取当前页面的URL信息
  • 原文地址:https://www.cnblogs.com/00isok/p/10798117.html
Copyright © 2011-2022 走看看