可持续字典树 Perfect Security
题目大意:给你两个序列,第二个序列可以任意进行排列变换,然后由这两个序列一一异或得到答案序列,要求答案序列的字典序最小。
可持续字典树与第K大可持续线段树的区别主要在于每个节点上 ,它多了一个记录值。
因为线段树肯定是对区间处理,要+1的,但是字典树是对点处理,这两个值都要记录。
#include<cstdio> #include<cstring> #include<algorithm> using namespace std; const int N=3e5+88; int sum[N*30][2],son[N*30][2],x,n,tot,a[N]; void update(int last,int cur,int num,int pos){ int temp=!!(num&(1<<pos)); sum[cur][temp]=sum[last][temp]+1; sum[cur][temp^1]=sum[last][temp^1]; son[cur][temp^1]=son[last][temp^1]; if(!pos) return; update(son[last][temp],son[cur][temp]=++tot,num,pos-1); } void query(int last,int cur,int num,int pos,int ans){ if(pos<0) {printf("%d ",ans);return;} int temp=!!(num&(1<<pos)); if(sum[cur][temp]-sum[last][temp]>0) --sum[cur][temp],query(son[last][temp],son[cur][temp],num,pos-1,ans); else --sum[cur][temp^1],query(son[last][temp^1],son[cur][temp^1],num,pos-1,ans|(1<<pos)); } int main(){ scanf("%d",&n); for(int i=1;i<=n;++i) scanf("%d",a+i); scanf("%d",&x); update(0,++tot,x,29); for(int i=2;i<=n;++i) { scanf("%d",&x); update((i-2)*30+1,++tot,x,29); } for(int i=1;i<=n;++i) query(0,(n-1)*30+1,a[i],29,0); puts(""); }