HDU 4825 Xor Sum (01字典樹)
阿新 • • 發佈:2018-12-11
題意:給你n個數字,再給你m次詢問,每次詢問給你一個數S,求n個數中和S異或最大的值。
題解:n方絕對超時。所以需要用的01字典樹這個東西。
01字典樹:本質和字典樹是一樣的。只不過他每個節點只存0和1這兩個東西。具體來說一下。我們可以把一個數字轉成2進位制數,把這個數字用來建樹。但是這個樹是從高位置向低位置建樹的。比如3不是11,而是0000……11。
對於建樹來說。若當前這個位置為1那麼就在tire【root】【1】這個位置加一個節點。若是0那就trie【root】【0】這個位置加一個節點。然後root = tire【root】【1/0】;
對於查詢來說。每次判斷tire【root】【i^1】是否有值。有就讓root = trie【root】【i^1】,沒有就root = tire【root】【i】;
具體看程式碼註釋:
#include<cstdio> #include<algorithm> #include<iostream> #include<cstring> typedef long long ll; using namespace std; const int maxn = 1e5+7; int ch[32*maxn][2]; ll val[32*maxn]; int sz; void init(){ memset(ch[0],0,sizeof(ch[0])); sz = 1; } void insert(ll a){ // 插入a int u = 0; // 從根節點0插入 for(int i = 32 ; i >= 0 ; i --){ // 從高位開始遍歷。 int c = ((a >> i) & 1); // 判斷 i 位置 是 0 還是 1 if(!ch[u][c]){ // 若當前節點沒有值 memset(ch[sz],0,sizeof(ch[sz])); // 建立一個新的節點。 val[sz] = 0; ch[u][c] = sz++; } u = ch[u][c]; // 遍歷到u的第c個兒子節點 } val[u] = a; // 葉子節點賦值 } ll query(ll a){ int u = 0; for(int i = 32 ; i >= 0 ; i --){ int c = ((a >> i) & 1); if(ch[u][c^1]) u = ch[u][c^1]; // 向不同的地方走 else u = ch[u][c]; } return val[u]; //返回葉子節點存的值。 } ll a[maxn]; int main(){ int t,n,m,kase = 0; scanf("%d",&t); while(t--){ init(); scanf("%d%d",&n,&m); for(int i = 1 ; i <= n ; i ++){ scanf("%lld",&a[i]); insert(a[i]); // 插入值 } printf("Case #%d:\n",++kase); for(int i = 1 ; i <= m ; i ++){ ll x; scanf("%lld",&x); printf("%lld\n",query(x)); // 查詢值 } } return 0; }