題意:給出\(a[1...n]\),共\(n\)次操做,每次刪除一個位置\(p_i\)(強制在線),此時區間會變爲兩個分離的區間,求每次操做的最大區間逆序對ios
首先要知道必要的工具,按權值創建的主席樹能夠在\(O(nlogn)\)內獲得任意區間長爲\(n\)的逆序對c++
但每次切除的點若是是不斷沿着邊來切,那麼要統計的區間總長是\(O(n^2)\)數組
考慮逆序對的貢獻是能夠互爲計算獲得的,那麼可否每次只對相對較小的區間的複雜度進行統計,獲得\(O(nlogn)\)的區間統計總長?工具
若是已知一個區間\([L,R]\)的總逆序對\(oldans\),切點爲\(M\),且更靠左邊,
那能夠對小區間的逆序數對進行暴力統計,獲得\([L,M-1]\)的全部相互貢獻,此時記爲\(ans1\)
而後再\(O(logn)\)計算\(a[M]\)對\([L,M-1]\)的貢獻,記爲\(tmp\)
最後詢問\(T[R]-T[K]\)的子樹中比\(a[i],i∈[L,M]\)小的個數,記爲\(tmp2\)
那麼區間\([L,M-1]\)的逆序數對爲\(ans1\),\([M+1,R]\)的逆序數對爲\(oldans-ans1-tmp-tmp2\)
以上操做都可以在\(O(nlogn)\)內完成,\(n\)爲小區間的長度ui
切點靠右同理,所以總的複雜度爲\(O(nlog^2n)\)spa
還有一些細節須要處理,如何在一開始就得知\([L,R]\)的總逆序數對,
初始化時先計算出\([1,n]\)的貢獻,剩下的必然在前面的操做中已經統計獲得\(ans1\)或\(ans2\)
考慮區間老是不斷分裂的,咱們能夠用簡單的平衡樹來維護位置\(M\)對應最近的\(L\)和\(R\)
而且答案老是對應於每個\(L\),都有一個惟一的\(R\)和\(ans\)相對應,這部分只需用簡單的數組便可獲得code
而\(ans\)的最優解須要在分裂時及時刪除對應的元素,再多拿一個multiset動態維護最大值便可ci
#include<iostream> #include<algorithm> #include<cstdio> #include<cstring> #include<set> #include<ctime> #define rep(i,j,k) for(register int i=j;i<=k;i++) #define rrep(i,j,k) for(register int i=j;i>=k;i--) #define erep(i,u) for(register int i=head[u];~i;i=nxt[i]) #define fastIO ios::sync_with_stdio(0);cin.tie(0);cout.tie(0) #define println(x) printf("%lld\n",(ll)(x)) using namespace std; typedef long long ll; typedef pair<ll,ll> pr; const int MAXN = 1e5+11; const int MAXM = 4e6+11; const int MOD = 142857; const int INF = 1<<30; int T[MAXN]; int a[MAXN],p[MAXN]; struct FST{ int cnt[MAXM]; int lc[MAXM],rc[MAXM]; int tot; void init(){tot=0;lc[tot]=rc[tot]=cnt[tot]=0;} int build(int l,int r){ int cur=++tot; lc[cur]=rc[cur]=cnt[cur]=0; if(l==r) return cur; int mid=l+r>>1; lc[cur]=build(l,mid); rc[cur]=build(mid+1,r); return cur; } int update(int old,int l,int r,int k,int v){ int cur=++tot; lc[cur]=lc[old]; rc[cur]=rc[old]; cnt[cur]=cnt[old]+v; if(l==r) return cur; int mid=l+r>>1; if(k<=mid) lc[cur]=update(lc[old],l,mid,k,v); else rc[cur]=update(rc[old],mid+1,r,k,v); return cur; } ll query(int cur1,int cur2,int l,int r,int L,int R){//l r if((cur2|cur1)==0) return 0; if(L<=l&&r<=R) return cnt[cur2]-cnt[cur1]; ll ans=0; int mid=l+r>>1; if(L<=mid) ans+=query(lc[cur1],lc[cur2],l,mid,L,R); if(R>mid) ans+=query(rc[cur1],rc[cur2],mid+1,r,L,R); return ans; } }fst; multiset<int> st; //multiset<pr> inv[MAXN]; ll inv[MAXN],invans[MAXN]; multiset<ll> ans; int main(){ #ifndef ONLINE_JUDGE freopen("stdin.txt","r",stdin); #endif int Test; scanf("%d",&Test); while(Test--){ int n; scanf("%d",&n); for(int i=1;i<=n;i++) scanf("%d",&a[i]); for(int i=1;i<=n;i++) scanf("%d",&p[i]); if(n==1){ printf("0\n"); continue; } fst.init(); T[0]=fst.build(1,n); for(int i=1;i<=n;i++){ T[i]=fst.update(T[i-1],1,n,a[i],1); } st.clear(); ans.clear(); st.insert(0),st.insert(n+1); for(int i=0;i<=n+1;i++) inv[i]=0; ll lastans=0; for(int i=1;i<=n;i++){ if(a[i]!=1){ lastans+=fst.query(T[i],T[n],1,n,1,a[i]-1); } } inv[1]=n,invans[1]=lastans; ans.insert(lastans); printf("%lld ",lastans); ll mx=lastans; for(int i=1;i<n;i++){ int k=lastans^p[i]; st.insert(k); multiset<int>::iterator it,lo,hi; lo=hi=it=st.find(k); --lo,hi++;//被砍的位置 int l=*lo,r=*hi; l++,--r;//實際操做的位置 ll oldans=invans[l]; ans.erase(ans.find(invans[l]));//這個答案必然無效 if(l==k&&r==k){ ans.insert(0),ans.insert(0); printf("%lld%c",lastans,i==n-1?'\n':' '); continue; } if(l==k){ ll tmp=0; if(a[k]>1) tmp=fst.query(T[k],T[r],1,n,1,a[k]-1); inv[k+1]=r; invans[k+1]=oldans-tmp; ans.insert(0); ans.insert(oldans-tmp); lastans=*--ans.end(); printf("%lld%c",lastans,i==n-1?'\n':' '); continue; } if(r==k){ inv[l]=0; ll tmp=0; if(a[k]<n) tmp=fst.query(T[l-1],T[k-1],1,n,a[k]+1,n); inv[l]=k-1; invans[l]=oldans-tmp; ans.insert(0); ans.insert(oldans-tmp); lastans=*--ans.end(); printf("%lld%c",lastans,i==n-1?'\n':' '); continue; } int len1=k-l+1,len2=r-k+1; ll ans1=0,ans2=0; if(len1<len2){ for(int j=l;j<k;j++){ if(a[j]>1){ ans1+=fst.query(T[j],T[k-1],1,n,1,a[j]-1); } } ll tmp=0; if(a[k]<n) tmp+=fst.query(T[l-1],T[k-1],1,n,a[k]+1,n); // multiset<pr>::iterator t=inv[l].begin(); ans2=invans[l]; ans2-=(ans1+tmp);//此時包括a[k]的逆序對貢獻 for(int j=l;j<=k;j++){ if(a[j]>1){ ans2-=fst.query(T[k],T[r],1,n,1,a[j]-1);//[k+1,r] } } inv[l]=k-1; invans[l]=ans1; inv[k+1]=r; invans[k+1]=ans2; }else{ for(int j=k+1;j<=r;j++){ if(a[j]>1){ ans1+=fst.query(T[j],T[r],1,n,1,a[j]-1);//[k+1,r] } } ll tmp=0; if(a[k]>1) tmp+=fst.query(T[k],T[r],1,n,1,a[k]-1);//[k+1,r] // multiset<pr>::iterator t=inv[l].begin(); ans2=invans[l]; ans2-=(ans1+tmp); for(int j=k;j<=r;j++){ if(a[j]<n){ ans2-=fst.query(T[l-1],T[k-1],1,n,a[j]+1,n);//[l,k-1] } } inv[l]=k-1; invans[l]=ans2; inv[k+1]=r; invans[k+1]=ans1;//.insert(pr(k-1,ans2)); //inv[k+1].insert(pr(r,ans1)); } ans.insert(ans1); ans.insert(ans2); printf("%lld%c",*--ans.end(),i==n-1?'\n':' '); lastans=*--ans.end(); } } return 0; }