可持续字典树 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("");
}

 

posted @ 2018-03-28 16:15  Billyshuai  阅读(245)  评论(0编辑  收藏  举报