CF923C Perfect Security
想在vj上做来着..结果vj半天登不上去...
错误思路:
暴力枚举TLE
错误思路2:
用cnt数组标记用了的数字,但注意如果我们只标记叶子结点,那么就会陷入死循环,因为每次都要走到底才能知道是否能用
正确思路:
用cnt数组标记当前结点的子节点的个数,因为可能存在重复数字,所以不能简单的赋值1,当我们在查询的时候,将要走的子节点个数-1即可.
要注意的是我们要插入树的是第二行的值,因为第一行的数字顺序是固定的
1 #include <iostream> 2 #include <cstring> 3 using namespace std; 4 #define pii pair<int,int> 5 const int N = 300010; 6 int a[N],son[N*32][2],cnt[N*32],idx;//不能到叶子结点才来看是否用过,不然每次都要重走 7 void insert_t(int x) 8 { 9 int p = 0; 10 for(int i=31;~i;i--){ 11 int t = x>>i&1; 12 if(!son[p][t]) son[p][t] = ++idx; 13 p = son[p][t]; 14 cnt[p]++; 15 } 16 } 17 int query(int x) 18 { 19 int p = 0,res = 0; 20 for(int i=31;~i;i--){ 21 int t = x>>i&1; 22 if(son[p][t]&&cnt[son[p][t]]){ 23 cnt[son[p][t]]--; 24 p = son[p][t]; 25 }else if((son[p][t]&&!cnt[son[p][t]])||!son[p][t]){ 26 cnt[son[p][!t]]--; 27 res+=(1<<i); 28 p = son[p][!t]; 29 } 30 } 31 return res; 32 } 33 int main() 34 { 35 int n; 36 scanf("%d",&n); 37 for(int i=1;i<=n;i++) scanf("%d",&a[i]); 38 for(int i=1;i<=n;i++){ 39 int y; scanf("%d",&y); 40 insert_t(y); 41 } 42 for(int i=1;i<=n;i++){ 43 if(i!=1) printf(" "); 44 printf("%d",query(a[i])); 45 } 46 printf("\n"); 47 return 0; 48 }