题目链接
题目大意:给你两个序列,第二个序列可以任意进行排列变换,然后由这两个序列一一异或得到答案序列,要求答案序列的字典序最小。
可持续字典树与第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(""); }