可持久化Trie樹

模板

const int MAX_N=301000;
int trie[MAX_N*32][2],latest[MAX_N*32];
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 ask(int k,int val,int deep,int limit){
 if(deep<0)
 return s[latest[k]]^val;
 int x=(val>>deep)&1;
 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);
}

用法

    scanf("%d%d",&n,&q);
    for(i=1;i<=n;i++){
        scanf("%d",&s[i]);
        root[i]=++tot;
        insert(root[i-1],root[i],s[i],i,31);
    }
    for(i=0;i<q;i++){
        scanf("%d%d%d",&x,&l,&r);
        l++;r++;
        cout<<ask(root[r],x,31,l)<<"\n";
    }

可持續化Trie樹相對於主席樹來說更方便,因爲Trie樹本身就是動態開點所以插入的時候直接在開一個新的頭節點然後以這個頭節點爲基礎擴展一條新邊即可,和主席樹不同的是可持續化Trie樹沒有利用前綴和,而是利用一個latest數組來存儲此節點等到達的所有值中在原輸入數組中的序號的最大值,這樣就可以查詢時利用root[r]所連接的所有節點都不會超過r的特性確定右邊界,然後再利用按位貪心來求是否存在滿足左邊界條件而且符合異或的值,最後求得的是符合條件的原輸入數組的序號。

問題 A: 腿部掛件

#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
const int MAX_N=301000;
int trie[MAX_N*32][2],latest[MAX_N*32];
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 ask(int k,int val,int deep,int limit){
 if(deep<0)
 return s[latest[k]]^val;
 int x=(val>>deep)&1;
 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 main(void){
    int n,q,x,i,l,r;
    scanf("%d%d",&n,&q);
    for(i=1;i<=n;i++){
        scanf("%d",&s[i]);
        root[i]=++tot;
        insert(root[i-1],root[i],s[i],i,31);
    }
    for(i=0;i<q;i++){
        scanf("%d%d%d",&x,&l,&r);
        l++;r++;
        cout<<ask(root[r],x,31,l)<<"\n";
    }
    return 0;
}
發佈了62 篇原創文章 · 獲贊 6 · 訪問量 1949
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章