HDU - 4757 Tree

HDU - 4757 Tree
題意:在樹上每個節點都有一個權值,每次詢問給出x,y和一個值z,求在樹上點x到點y的路徑上每個點的權值異或z之後的最大值。
思路:可持久化01字典樹,利用LCA,即兩段路徑,x到LCA(a,b)和y到LCA(a,b),可以按dfs序來可持久化,比如root[i]可以接他的父親即root[fa[i]]。挺有用的想法,應該可以擴展到樹上主席樹。

#include<iostream>
#include<cstdio>
#include<vector>
#include<cstring>
#include<algorithm>
using namespace std;
const int MAX_N=101000;
vector<int>edge[MAX_N];
int dp[MAX_N][20],have[MAX_N],d[MAX_N],N,log_2[MAX_N];
void dfs(int now){
 int i;
 for(i=0;i<edge[now].size();i++){
  if(!have[edge[now][i]]){
   have[edge[now][i]]=1;
   dp[edge[now][i]][0]=now;
   d[edge[now][i]]=d[now]+1;
   dfs(edge[now][i]);
   have[edge[now][i]]=0;
  }
 }
}
int LCA(int a,int b){
 int k=log_2[N],i;
 if(d[a]<d[b]){
  int c=a;
  a=b;
  b=c;
 }
 while(d[a]!=d[b]){
  for(i=k;i>=0;i--){
   if(d[dp[a][i]]>=d[b])
   a=dp[a][i];
  }
 }
 if(a==b){
  return b;
 }
 for(i=k;i>=0;i--){
  if(dp[a][i]!=dp[b][i]){
   a=dp[a][i];
   b=dp[b][i];
  }
 }
 return dp[a][0];
}
int trie[MAX_N*20][2],latest[MAX_N*20];
int s[MAX_N],root[MAX_N],tot;
void insert(int k,int k1,int val,int i,int deep){
 if(deep<0){
  latest[k1]=i;
  return;
 }
 int x=(val>>deep)&1;
 if(k)
 trie[k1][x^1]=trie[k][x^1];
 trie[k1][x]=++tot;
 insert(trie[k][x],trie[k1][x],val,i,deep-1);
 latest[k1]=max(latest[trie[k1][0]],latest[trie[k1][1]]);
}
int dft[MAX_N],dfx[MAX_N];
int ask(int k,int val,int deep,int limit){
 if(deep<0)
 return s[dfx[latest[k]]]^val;
 int x=(val>>deep)&1;
 //cout<<latest[trie[k][x^1]]<<" "<<limit<<" "<<deep<<"\n";
 if(latest[trie[k][x^1]]>=limit)
 return ask(trie[k][x^1],val,deep-1,limit);
 else
 return ask(trie[k][x],val,deep-1,limit);
}
int cnt=0;
void dfs_(int now,int fa){
    int i;
    dft[now]=++cnt;
    dfx[cnt]=now;
    root[now]=++tot;
    insert(root[fa],root[now],s[now],cnt,17);
    //cout<<root[now]<<" "<<dft[now]<<" "<<now<<" "<<fa<<" hi\n";
    for(i=0;i<edge[now].size();i++){
        int to=edge[now][i];
        if(to!=fa){
            dfs_(to,now);
        }
    }
}
int main(void){
    int m,i,j,u,v;
    for(i=1;i<=100000;i++)
    log_2[i]=log_2[i-1]+(1<<log_2[i-1]==i);
    while(scanf("%d%d",&N,&m)!=EOF){
    for(i=1;i<=N;i++){
        edge[i].clear();
        have[i]=0;
        scanf("%d",&s[i]);
    }
    for(i=0;i<N-1;i++){
        scanf("%d%d",&u,&v);
        edge[u].push_back(v);
        edge[v].push_back(u);
    }
    tot=0;
    cnt=0;
    memset(trie,0,sizeof(trie));
    memset(latest,0,sizeof(latest));
    dfs_(1,0);
    have[1]=1;
    dfs(1);
    d[0]=-1;
    for(i=1;i<=log_2[N];i++){
        for(j=1;j<=N;j++){
            dp[j][i]=dp[dp[j][i-1]][i-1];
        }
    }
    int a,b,z;
    for(i=0;i<m;i++){
        scanf("%d%d%d",&a,&b,&z);
        int pre=LCA(a,b);
        //cout<<dft[pre]<<"hi\n";
        int ans=max(ask(root[a],z,17,dft[pre]),ask(root[b],z,17,dft[pre]));
        cout<<ans<<"\n";
    }
    }
    return 0;
}
發佈了62 篇原創文章 · 獲贊 6 · 訪問量 1957
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章