大致题意:给你一个序列,每次删掉序列中的一个数字,使得原本的一段变成两段。每次在删除之前,输出所有段中,逆序对数量最多的逆序对,强制在线。
对于这道题,你需要有一定的胆量。
对于逆序对,如果暴力求的话,其复杂度是O(NlogN)的,这个用很多中方式都可以求出来。现在考虑按顺序删掉数字,每次删掉数字之后,拆成两个新的区间,这样在所有区间中,逆序对最多是多少。考虑,删除之后,会产生两个新的区间,如果直接暴力重新算,显然会超时,所以可以利用一些原有的性质。
一个区间拆成两个之后,原本的大区间逆序对可以分为三个部分。一是左区间的逆序对个数;二是右区间的逆序对数;三是横跨两个区间的逆序对数目。我们大胆尝试,暴力去求小区间的逆序对数目,复杂度为O(Len log Len)。然后对于大的区间,我们考虑用总的逆序对,减去小区间逆序对,再减去横跨两个区间的逆序对。对于横跨两个区间的逆序对,我们可以遍历小的区间,然后查找大的区间中比枚举数字小(大)的数字个数。如此一次的复杂度就是O(smalen log biglen)。
我们再来考虑一下这个复杂度计算。我们的最后目标是把所有的区间分成单位区间,那么,如果把分割画到同一层,最后可以变成类似线段树的结构。第i层的区间数是。可以证明,最坏的情况是每一次都是平均分,那么对于平均分每一层时间复杂度就是O(NlogN),由于树总共右logN层,所以复杂度就是O(NlogNlogN),两个logN的复杂度做出这题足矣。
具体做法,需要求一个区间内大于某个数字或者小于某个数字的个数,这个可以用主席树来做。但是实际上,注意到,处理每一个区间的时间是NlogN的,所以用很多方法都可以做,最简单的就是用pbds的红黑树,但是常数可能会大一些。具体见代码:
#include<bits/stdc++.h>
#define mod 256
#define LL long long
#define pb push_back
#define lb lower_bound
#define ub upper_bound
#define INF 0x3f3f3f3f
#define sf(x) scanf("%d",&x)
#define sc(x,y,z) scanf("%d%d%d",&x,&y,&z)
#define clr(x,n) memset(x,0,sizeof(x[0])*(n+5))
#define file(x) freopen(#x".in","r",stdin),freopen(#x".out","w",stdout)
using namespace std;
const int N = 100010;
int rt[N],a[N];
struct Persistent_SegTree
{
struct node{int l,r,sum;} T[N<<5];
int cnt; void init(){cnt=0;T[0]={0,0,0};}
void ins(int &i,int old,int l,int r,int x)
{
i=++cnt;
T[i]=T[old];
T[i].sum++;
if (l==r) return;
int mid=(l+r)>>1;
if (x<=mid) ins(T[i].l,T[old].l,l,mid,x);
else ins(T[i].r,T[old].r,mid+1,r,x);
}
int query(int i,int j,int x,int l,int r)
{
if (l==r) return 0;
if (T[i].sum==T[j].sum) return 0;
int mid=(l+r)>>1;
int tmp=T[T[i].l].sum-T[T[j].l].sum;
if (mid>=x) return query(T[i].l,T[j].l,x,l,mid);
else return tmp+query(T[i].r,T[j].r,x,mid+1,r);
}
} Persist;
unordered_map<int,LL> mp;
multiset<LL> st;
set<int> ss;
int mx;
int main()
{
int T; sf(T);
while(T--)
{
LL ans=0; mx=0;
int n; sf(n);
st.clear(); ss.clear();
mp.clear(); Persist.init();
ss.insert(0); ss.insert(n+1);
for(int i=1;i<=n;i++)
{sf(a[i]); mx=max(mx,a[i]);}
mx++;
for(int i=1;i<=n;i++)
{
ans+=(i-1)-Persist.query(rt[i-1],rt[0],a[i]+1,1,mx);
Persist.ins(rt[i]=0,rt[i-1],1,mx,a[i]);
}
st.insert(ans); mp[0]=ans;
for(int i=1;i<=n;i++)
{
auto pp=st.end();
pp--; ans=*pp;
if (i!=n) printf("%lld ",ans);
else printf("%lld\n",ans);
int x; sf(x);
x^=ans; auto pos=ss.ub(x);
int l,r=*pos; pos--; l=*pos;
st.erase(st.lb(mp[l]));
LL tmp=0,temp=0,tt=mp[l];
if (x-l>r-x)
{
for(int j=x+1;j<r;j++)
tmp+=x-l-Persist.query(rt[x],rt[l],a[j]+1,1,mx);
for(int j=x+1;j<r-1;j++)
temp+=Persist.query(rt[r-1],rt[j],a[j],1,mx);
mp[x]=temp; st.insert(temp);
int xx=x-1-l-Persist.query(rt[x-1],rt[l],a[x]+1,1,mx);
mp[l]=tt-tmp-temp-xx; st.insert(tt-tmp-temp-xx);
ss.insert(x);
} else
{
for(int j=l+1;j<x;j++)
tmp+=Persist.query(rt[r-1],rt[x-1],a[j],1,mx);
for(int j=l+1;j<x-1;j++)
temp+=Persist.query(rt[x-1],rt[j],a[j],1,mx);
mp[l]=temp; st.insert(temp);
int xx=Persist.query(rt[r-1],rt[x],a[x],1,mx);
mp[x]=tt-tmp-temp-xx; st.insert(tt-tmp-temp-xx);
ss.insert(x);
}
}
}
return 0;
}