1. 程式人生 > >Codeforces 948D Perfect Security(字典樹)

Codeforces 948D Perfect Security(字典樹)

out force 開始 problem codeforce int get 字典 數量

題目鏈接:Perfect Security

題意:給出N個數代表密碼,再給出N個數代表key。現在要將key組排序,使key組和密碼組的亦或所形成的組字典序最小。

題解:要使密碼組裏面每個數都找到能使其亦或和最小的數可以將key建成一棵字典樹(這裏建樹方式很關鍵,可以每個數都從2^31開始建樹,這樣可以使我們在遍歷樹查詢更加方便)。之後再遍歷密碼組每次在字典樹裏面找到一個能使它亦或和最小的數,再將這個數從字典樹中刪掉。。。 字典樹太久不寫,很多東西都忘記了!

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 const int
MAX_N = 3e5+9; 4 const int INF = 1e9+9; 5 int tran[MAX_N*35][2]; //跳轉到下一個節點的數組 6 int sum[MAX_N*35],ans[MAX_N],A[MAX_N],P[MAX_N]; //sum - 記錄每個節點記錄的數的數量 7 int N,M,T,S,siz; 8 void init(){ 9 for(int i=0;i<MAX_N;i++){ 10 tran[i][0] = tran[i][1] = 0; 11 sum[i] = 0; 12 } 13 siz = 0
; 14 } 15 void _insert(int x){ 16 int now = 0; 17 for(int i=31;i>=0;i--){ //從31開始就可以保證從高位開始建樹了 18 int t = 0; 19 if(x & (1<<i)) t = 1; 20 if(!tran[now][t]) tran[now][t] = ++siz; // 這裏siz指的時節點的編號,這裏如果下一個指向的節點沒有的話就新生成一個節點給它。 21 sum[tran[now][t]] ++; //節點上記錄的數的數量加一
22 now = tran[now][t]; //跳轉到下一個節點 23 } 24 } 25 void query(int id , int x){ 26 int now = 0; 27 int res = 0; 28 for(int i=31;i>=0;i--){ 29 int t =0; 30 if(x & (1<<i)) t = 1; 31 if(!sum[tran[now][t]]){ 32 res += (1<<i); 33 t = 1-t; 34 } 35 sum[tran[now][t]] --; 36 now = tran[now][t]; 37 38 } 39 ans[id] = res; 40 } 41 int main() 42 { 43 while(cin>>N) 44 { 45 init(); 46 for(int i=0;i<N;i++){ 47 scanf("%d",&A[i]); 48 } 49 for(int i=0;i<N;i++){ 50 scanf("%d",&P[i]); 51 _insert(P[i]); 52 } 53 for(int i=0;i<N;i++){ 54 query(i,A[i]); 55 cout<<ans[i]<<" "; 56 } 57 cout<<endl; 58 59 } 60 return 0; 61 }

Codeforces 948D Perfect Security(字典樹)