D、Vitya and Strange Lesson(字典树模版)

xiaoxiao2021-02-28  101

很多二进制关于异或求最值的问题,都可以转换为字典树来求,然后在字典树上往最左边或者最右边跑,使得结果达到最值。

这题就每次异或改变的值可以当作改变每次异或的查询使得字典树不变。

然后用num(不计算重复)来计算每个分支里面的数的个数,如果数满了就进入到另外一个分支(使得绕过所有最小值的最小值)

然后当res=0的时候,也就是满足这个分支里没有任何数,那么就不再加任何数了

#include <stdio.h> #include <string.h> #include<iostream> #define MAX(a,b) ((a)>(b)?(a):(b)) #define NODE 3200010 #define N 300010 using namespace std; int n; int v[N]; int node; int next[NODE][2]; int end[NODE]; int num[NODE][2]; bool vis[NODE]; void add(int cur,int k) { memset(next[node],0,sizeof(next[node])); end[node]=0; next[cur][k]=node++; } int cal(int x) { int i,k,cur=0,t1; int res=0; for(i=19;i>=0;i--) { k=((1<<i)&x)?1:0; if(num[cur][k]>=1<<(i)){ res+=1<<i; cur=next[cur][1-k]; }else{ cur=next[cur][k]; } if(cur==0)break; //这里是为了当进入到一个个数为0的分支,可以直接break } //return (x^end[cur]); 如果是求最大值 return res; } int main() { int i,j,k,x,cur; int ans,m; //freopen("in.txt","r",stdin); while(~scanf("%d %d",&n,&m)) { node=1; memset(next[0],0,sizeof(next[0])); for(i=0;i<n;i++) { scanf("%d",&x); if(vis[x])continue; vis[x]=1; v[i]=x; cur=0; for(j=19;j>=0;j--) { k=((1<<j)&x)?1:0; if(next[cur][k]==0)add(cur,k); num[cur][k]++; cur=next[cur][k]; } end[cur]=x; } int t1,t2; t1=0; for(ans=i=0;i<m;i++){ //求最大值是max(ans,cal(v[i])) cin >> t2; t1^=t2; cout << cal(t1) << endl; } } return 0; }

转载请注明原文地址: https://www.6miu.com/read-17550.html

最新回复(0)