http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemCode=4053
已知一个区间的逆序数 将其分成两子区间后 分别求出两子区间的逆序数 可以想到只暴力求其中一边 根据贡献算出另一边 但是如果划分的位置正好是1 2 ... n可能退化为n^2 但是可以每次只暴力相对较小的那个区间 这样在最坏情况下也是logn的 后来知道这么搞叫启发式合并。。
其余就是主席树和线段树维护一下
using namespace std;
typedef long long ll;
const int maxn=1e5+10;
struct node
{
ll val;
int l,r;
};
node tree[20*maxn];
ll maxx[4*maxn];
ll pos[maxn];
int ary[maxn],root[maxn];
int n,num;
int build(int l,int r)
{
int cur,m;
cur=num++;
tree[cur].l=0,tree[cur].r=0,tree[cur].val=0;
if(l==r) return cur;
m=(l+r)/2;
tree[cur].l=build(l,m);
tree[cur].r=build(m+1,r);
return cur;
}
int updateI(int rot,int tar,int l,int r)
{
int cur,m;
cur=num++;
tree[cur]=tree[rot];
tree[cur].val++;
if(l==r) return cur;
m=(l+r)/2;
if(tar<=m) tree[cur].l=updateI(tree[rot].l,tar,l,m);
else tree[cur].r=updateI(tree[rot].r,tar,m+1,r);
return cur;
}
ll queryI(int lrot,int rrot,int pl,int pr,int l,int r)
{
ll res;
int m;
if(pl<=l&&r<=pr) return tree[rrot].val-tree[lrot].val;
res=0,m=(l+r)/2;
if(pl<=m) res+=queryI(tree[lrot].l,tree[rrot].l,pl,pr,l,m);
if(pr>m) res+=queryI(tree[lrot].r,tree[rrot].r,pl,pr,m+1,r);
return res;
}
ll getniI(int l,int r)
{
ll res;
int i;
res=0;
for(i=l;i<=r;i++) if(ary[i]<n) res+=queryI(root[l-1],root[i-1],ary[i]+1,n,1,n);
return res;
}
ll getniII(int tp,int l,int r,int pl,int pr)
{
ll res;
int i;
res=0;
for(i=l;i<=r;i++){
if(!tp){
if(ary[i]<n) res+=queryI(root[l-1],root[i-1],ary[i]+1,n,1,n);
if(ary[i]>1) res+=queryI(root[pl-1],root[pr],1,ary[i]-1,1,n);
}
else{
if(ary[i]<n) res+=queryI(root[l-1],root[i-1],ary[i]+1,n,1,n);
if(ary[i]<n) res+=queryI(root[pl-1],root[pr],ary[i]+1,n,1,n);
}
}
return res;
}
void pushup(int cur)
{
maxx[cur]=max(maxx[2*cur],maxx[2*cur+1]);
}
void updateII(int tar,ll val,int l,int r,int cur)
{
int m;
if(l==r){
maxx[cur]=val;
return;
}
m=(l+r)/2;
if(tar<=m) updateII(tar,val,l,m,2*cur);
else updateII(tar,val,m+1,r,2*cur+1);
pushup(cur);
}
ll queryII(int tar,int l,int r,int cur)
{
int m;
if(l==r) return maxx[cur];
m=(l+r)/2;
if(tar<=m) return queryII(tar,l,m,2*cur);
else return queryII(tar,m+1,r,2*cur+1);
}
int main()
{
set <int> st;
set <int> ::iterator it;
ll res,lef,rgt;
int t,i,j,p,l,r;
scanf("%d",&t);
while(t--){
scanf("%d",&n);
for(i=1;i<=n;i++) scanf("%d",&ary[i]);
for(i=1;i<=n;i++) scanf("%lld",&pos[i]);
num=0;
root[0]=build(1,n);
for(i=1;i<=n;i++) root[i]=updateI(root[i-1],ary[i],1,n);
res=getniI(1,n);
for(i=1;i<=4*n;i++) maxx[i]=0;
updateII(1,res,1,n,1);
st.clear();
st.insert(0),st.insert(n+1);
for(i=1;i<=n;i++){
printf("%lld",maxx[1]);
if(i<n) printf(" ");
else printf("\n");
p=maxx[1]^pos[i];
it=st.upper_bound(p);
r=*it-1;
it--;
l=*it+1;
st.insert(p);
res=queryII(l,1,n,1);
updateII(l,0,1,n,1);
if(p-l<r-p){
lef=getniI(l,p-1);
rgt=res-getniII(0,l,p,p+1,r);
updateII(l,lef,1,n,1),updateII(p+1,rgt,1,n,1);
}
else{
lef=res-getniII(1,p,r,l,p-1);
rgt=getniI(p+1,r);
updateII(l,lef,1,n,1),updateII(p+1,rgt,1,n,1);
}
}
}
return 0;
}
/*
1
10
9 7 1 4 7 8 5 7 4 8
21 8 15 5 9 2 4 5 10 6
*/