4053(2018 青島網路賽)
阿新 • • 發佈:2018-12-10
題目連結:點選這裡
解題思路:
如果我們已經知道區間(l,r)的逆序對值W,現在對m進行標記,l<=m<=r.那麼區間就被分為了兩塊[l,m),(m,r].
對於新得到的兩個子區間,設區間長度小的那個子區間的長度為k,區間標記為rt
那麼我們可以利用主席樹在O(k*log(k))求出rt逆序對值,那麼我們如何得到另一個區間的值呢?
設點i的正貢獻為:[1,i-1]大於a[i]的個數,反貢獻為[i+1,r]小於a[i]的貢獻
很容易找到正貢獻累加就是[1,n]的總逆序對個數,且正貢獻總和於反貢獻總和是相等的.
對於小的區間在左邊,右區間的逆序對值 = W - (l,m)的反貢獻和
對於小的區間在右邊,左區間的逆序對值 = W - (m,r)的正貢獻和
時間複雜度證明:
對於一個點i被暴力求出貢獻值得情況是他在小的子區間,子區間大小<=原區間大小/2,所以i點最多被暴力log(n)次
所以總時間複雜度為O(n*log(n)*log(n))
#include<bits/stdc++.h> #define lson l,mid #define rson mid+1,r using namespace std; typedef long long ll; int n,m; const int mx = 1e5+10; int a[mx],root[mx],sma[mx],big[mx]; int ls[20*mx],rs[20*mx],sum[20*mx],size; ll pv[mx]; multiset <ll> mlst; set <int> st; void update(int x,int &y,int l,int r,int v,int M) { y = ++size; ls[y] = ls[x],rs[y] = rs[x],sum[y] = sum[x] + v; int mid = (l+r)>>1; if(l==r) return ; if(M<=mid) update(ls[x],ls[y],lson,v,M); else update(rs[x],rs[y],rson,v,M); } int query1(int x,int l,int r,int M) { if(l>M) return sum[x]; int mid = (l+r)>>1; if(l==r) return 0; int ans = query1(rs[x],rson,M); if(M<mid) ans += query1(ls[x],lson,M); return ans; } int query2(int x,int l,int r,int M) { if(r<M) return sum[x]; int mid = (l+r)>>1; if(l==r) return 0; int ans = query2(ls[x],lson,M); if(M>mid+1) ans += query2(rs[x],rson,M); return ans; } void init() { sum[0] = ls[0] = rs[0] = size = 0; mlst.clear();st.clear(); mlst.insert(0); st.insert(0);st.insert(n+1); } void deal(int l,int mid,int r) { int L = mid-l,R = r-mid; ll ret = 0,ans = 0; if(L||R){ if(L<=R){ for(int i=l+1;i<mid;i++) ret += big[i]-query1(root[l-1],1,n,a[i]); if(L) mlst.insert(ret); for(int i=l;i<=mid;i++) ans += query2(root[r],1,n,a[i])-sma[i]; mlst.insert(ans = pv[l]-ans); }else{ for(int i=mid+2;i<=r;i++) ans += big[i]-query1(root[mid],1,n,a[i]); if(R) mlst.insert(ans); for(int i=mid;i<=r;i++) ret += big[i]-query1(root[l-1],1,n,a[i]); mlst.insert(ret = pv[l]-ret); } } mlst.erase(mlst.find(pv[l])); pv[l] = ret,pv[mid+1] = ans; } int main() { int t,cas = 1; scanf("%d",&t); while(t--){ scanf("%d",&n); init(); ll ans = 0; for(int i=1;i<=n;i++) scanf("%d",a+i); for(int i=1;i<=n;i++){ update(root[i-1],root[i],1,n,1,a[i]); big[i] = query1(root[i-1],1,n,a[i]); sma[i] = query2(root[i-1],1,n,a[i]); ans += big[i]; } mlst.insert(ans); pv[1] = ans; for(int i=1;i<=n;i++){ ll ret = *(--mlst.end()); scanf("%d",&m); printf("%lld%c",ret,i==n?'\n':' '); if(ret==0) continue; m = ret ^ m; auto it = st.lower_bound(m),ip = it; deal(*(--ip)+1,m,*it-1); st.insert(m); } } return 0; }