HDU 6191 2017廣西邀請賽Query on A Tree:可持久化01字典樹(區間抑或最大值查詢)
阿新 • • 發佈:2019-01-31
題意:給出一棵n(<=1e5)個點的樹,每個點有一個權,詢問q(<=qe5)次,每次詢問(nod,val),計算出以nod為根的子樹上的所有點,權抑或val的最大值是多少。
題解:基本上是個板子題吧。直接講方法了。。直接上DFS序+可持久化01字典樹就行了。可持久化01字典樹可以用32步查得一個區間內某個數字和val抑或得到的最大答案,那麼DFS序一下就可以把子樹搞成區間。然後完美解決。
可持久化01字典樹:可以理解成在字典樹的每個節點上弄了個字首和一樣的東西吧,重點在空間複用。每個字典樹節點增加sum域,記錄前邊數字中有多少個數字走到這個節點。每次加入一個新的數字,都開一個“全新”的字典樹,把每個樹的根都記下來。這個新的字典樹包括了之前加入的所有數字,也包括當前數字,但是這樣超級浪費空間,怎麼辦呢,我們知道 加入一個新的數字,和上一棵樹最多隻會有32個點不同。那麼新樹和上一個樹不變的點就直接用上一棵樹的就行了(兩個樹相同的部分重合起來,不需要新開點來存了),把新的點的sum給更新了就行了。
查詢:查詢區間[ l , r ]時,同時查root[ l-1 ] 和 root[ r ]這兩棵樹,同時往下走,如果sum不同, 說明[ l , r ]區間內的某個數字出現在這條鏈路上,那麼就可以往這個方向走。然後取抑或最大操作和普通01字典樹無異,都是貪心的高位能取不同就不同,否則取相同(相同和不同必然可以取一個,要不然豈不是說明這個區間內沒有數字了。。。)。
Flag:01字典樹什麼的不可能寫WA的hhhhhh(除非是能把x寫成y的lowB葫蘆娃)
以及博主最近沉迷冒險島2。。。。。。沒救了
Code:
#include<bits/stdc++.h> using namespace std; const int MAX = 1e5+100; int bas[35]; int nxt[MAX<<5][2]; int root[MAX]; int sum[MAX<<5]; int n,q; vector<int>E[MAX]; int st[MAX],en[MAX],rk[MAX]; int a[MAX]; int cnt; int tot; void sheet(){ bas[0]=1; for (int i=1;i<=30;i++){ bas[i] = bas[i-1]<<1; } } void init(){ for (int i=0;i<=n;i++){ E[i].clear(); } cnt =tot=0; memset(nxt[0],0,sizeof nxt[0]); } void input(){ for (int i=1;i<=n;i++){ scanf("%d",a+i); } for (int u=2;u<=n;u++){ int v; scanf("%d",&v); E[u].push_back(v); E[v].push_back(u); } } void dfs(int node ,int father ){ st[node] = ++tot; rk[tot] = node; for (int des:E[node]){ if(des==father){ continue; } dfs(des,node); } en[node] = tot; } int create(){ cnt++; memset(nxt[cnt],0,sizeof nxt[cnt]); return cnt; } int insert(int rt,int val){ int y = ++cnt; int x = rt; int res = y; for (int i=30;i>=0;i--){ sum[y] = sum[x]+1; nxt[y][0] = nxt[x][0]; nxt[y][1] = nxt[x][1]; int t = val&bas[i]; t>>=i; nxt[y][t] = create(); y = nxt[y][t]; x = nxt[x][t]; } sum[y] = sum[x]+1; return res; } int query(int l,int r,int val){ int res =0; int x = l; int y = r; for (int i=30;i>=0;i--){ int t = val&bas[i]; t>>=i; if (sum[nxt[y][!t]]-sum[nxt[x][!t]]){ y = nxt[y][!t]; x = nxt[x][!t]; res+=bas[i]; }else{ y = nxt[y][t]; x = nxt[x][t]; } } return res; } void solve(){ dfs(1,0); for (int i=1;i<=n;i++){ root[i] = insert(root[i-1],a[rk[i]]); } while (q--){ int nod,x; scanf("%d%d",&nod,&x); printf("%d\n",query(root[st[nod]-1],root[en[nod]],x)); } } int main(){ sheet(); while (scanf("%d%d",&n,&q)!=EOF){ init(); input(); solve(); } return 0; }