Tree

hdu 4757
树链剖分 + 可持久化trie树
到现在才有点大彻大悟,可持久化trie的作用就是可以查询到历史版本, 那么既然可以,最最暴力的做法,就是每一个点都建立一个新的,这个新的版本既包含旧版本, 也包含最新的结点, 但是空间复杂度实在是不敢恭维, 故大佬们想的做法就是在暴力的基础上进行修改, 每个点依旧建立新版本, 但是只建立之前旧版本没有的东西, 然后再把旧版本和这个空间占用上面很小的结点联系起来, 这样既降低了空间复杂度, 还能新老版本一块使用, 每个结点都代表一个新版本 , 然后还和旧版本连接在一起,例如rt[x] ,表示第x个结点所在的新版本, 那么这个rt[x] , 里面只存储了这个新版本的信息和x - 1 的联系, 然后rt[x - 1] 存储的是x - 1 这个新版本的信息, 链接的是x - 2 ,这个旧版本,所以这样就实现了可持久化数据结构,
然后就在处理好树链剖分的树上结构进行可持久化trie树,
建立的话旧版本就是父亲结点, 新版本就是孩子结点了。

#include <bits/stdc++.h>
using namespace std ;
const int N = 1e5 + 10 ;
int e[N << 1] , ne[N << 1] , num[N << 5] , h[N << 1] , size[N <<2] , son[N << 2] , ch[N << 5][2] ;
int n , m , idx , cnt  ; 
int fa[N << 1] , deep[N << 1] , top[N << 1] , rt[N << 1] , val[N<< 1];



 void dfs1(int u , int f , int d)
{
    size[u] = 1 , son[u] = 0 , fa[u] = f , deep[u] = d;
    for(int i = h[u] ; ~i ;i = ne[i]) 
     {
         int v = e[i] ;
         if(v == f) continue ;
         dfs1(v , u , d + 1 ) ;
         size[u] += size[v] ;
         if(!son[u] || size[son[u]] < size[v])
          son[u] = v ;
     }
}
void dfs2(int u , int tp)
{
    top[u] = tp ;
    if(!son[u]) return ;
    dfs2(son[u] , tp) ;
    for(int i = h[u] ; ~i ; i = ne[i])
     {
         int v = e[i] ;
        if(v == fa[u] || v == son[u]) continue ;
        dfs2(v , v) ;
     }
}
int lca(int x , int y)
{
    while(top[x] != top[y])
     {
         if(deep[top[x]] < deep[top[y]]) 
          swap(x , y) ;
         x = fa[top[x]] ;
     }
     return deep[x] > deep[y] ? y : x ;
} 
void add(int a, int b)
{
    e[idx] = b , ne[idx] = h[a] , h[a] = idx ++ ;
}
void insert(int last , int &now , int x)
{
    now = ++ cnt ;
    int p = now ;
    for(int i = 30 ;i >= 0;i --)
     {
         int id = (x >> i) & 1 ;
         ch[p][id] = ++ cnt ;
         ch[p][id ^ 1] = ch[last][id ^ 1] ;
         num[p] = num[last] + 1;
         p = ch[p][id] , last = ch[last][id] ;
     }
     num[p] = num[last] + 1 ;
}
void dfs(int u)
{
    insert(rt[fa[u]] , rt[u] , val[u]) ;
    for(int i = h[u] ; ~i ;i = ne[i])
     {
         int v = e[i] ;
         if(v == fa[u]) 
          continue ;
         dfs(v) ;
     }
}
int ask(int x , int y , int z , int v) 
{
    int res = v ^ val[z] , ans = 0 ;
    z = rt[z] ;
    for(int i  = 30 ;i >= 0 ;i --)
     {
         int id = (v >> i) & 1 ;
         int t = num[ch[x][id ^ 1]] + num[ch[y][id ^ 1]] - 2 * num[ch[z][id ^ 1]] ;
         if(t > 0) 
          ans += 1 << i , id ^= 1 ;
         x =ch[x][id] , y = ch[y][id] , z = ch[z][id] ;
     }
     return max(ans , res) ;
}
int main()
{
   while(~scanf("%d%d" , &n , &m))
    {
        idx = 0 , cnt = 0 ;
        memset(h , -1 , sizeof h) ;
        for(int i = 1 ;i <= n ;i ++)
         scanf("%d" , &val[i]) ;
        for(int i = 1; i < n ;i ++)
         {
             int u , v ;
             scanf("%d%d" , &u , &v) ;
             add(u , v) , add(v , u) ;
         }
        dfs1(1 , 0 , 1) , dfs2(1 , 1) , dfs(1) ;
        for(int i = 1; i <= m ;i ++)
         {
             int x , y , z ;
             scanf("%d%d%d" , &x , &y , &z) ;
             printf("%d
" , ask(rt[x] , rt[y] , lca(x , y) , z))  ;
         }
    } 
   return 0 ;
}
每次做题提醒自己:题目到底有没有读懂,有没有分析彻底、算法够不够贪心、暴力够不够优雅。
原文地址:https://www.cnblogs.com/spnooyseed/p/12870873.html