【原題】
N<=100000 M<=50000
【題外話】一直想A了這道題。真累啊!開始的想法是——倒著做,一個一個添加,套一個樹狀數組,然後每次用平衡樹去尋找。顯然,現在我只會SPLAY,而且代碼長,效率渣。今天和SYF大神一起看hzwer大神的博客,加之哲大爺的一語道破,總算會了樹狀數組套主席樹的方法。
【主要思路】首先用樹狀數組/歸並排序/歸並樹(時代的眼淚)求出總的序列中的逆序對個數。每次刪掉的時候,用樹狀數組維護位置(1--x-1或x+1--n),並且用權值線段樹維護權值信息。
【詳細算法】
①在之前的計算總的逆序對個數的時候,我們可以順帶的算出front[i]和back[i],表示第i個點之前有front[i]個數比他大,之後有back[i]個數比他小。
②起初剛開始做的時候,主席樹內部是空的。因此我們要轉化——我們本來計算的是刪掉某個數後,將會減少所剩的數列中的多少的逆序對(即對所剩的序列產生多少的貢獻);現在我們改成:刪掉某個數後,將會對主席樹中已經插入的一些節點產生多少的貢獻。這樣算出來後,用front或back減一下即可。
舉個例子。比如有數列5,4,3,2,1,已經刪掉了4和1,ans值是3。現在我們要刪掉3了。在主席樹中,已添加的節點是5和2。通過計算,5,3,2會在3的前面產生一個逆序對,在3的後面產生一個逆序對。而front[3]=2,back[3]=2,那麼我們可以知道,ans需要減去front[3]-1與back[3]-1,即最後ans只剩下了1。
③後來套的樹狀數組具體是怎麼實現的呢?比如我們要計算或更新l~r范圍內主席樹中的某個或某些權值的個數。我們可以轉化為計算或更新1--l-1與1--r的前綴,再相減即可。而前綴是可以用樹狀數組解決的。
【代碼】
#include#include #define N 100005 #define L(x) (x&-x) using namespace std; typedef long long LL;LL ans; struct arr{int l,r;LL sum;}a[6000000]; int front[N],back[N],c[N],root[N],pos[N],data[N],A[31],B[31]; int n,node,del,x,m,i; inline int ask(int x){int s=0;for (;x;x-=L(x)) s+=c[x];return s;} inline void up(int x){for (;x<=n;x+=L(x)) c[x]++;} inline LL ask_more(int l,int r,int num) { if (l>r) return 0;l--;A[0]=B[0]=0; for (int i=l;i;i-=L(i)) A[++A[0]]=root[i]; for (int i=r;i;i-=L(i)) B[++B[0]]=root[i]; l=1;r=n;LL sum=0; while (l!=r) { int mid=(l+r)>>1; if (num<=mid) { for (int i=1;i<=B[0];i++) sum+=a[a[B[i]].r].sum; for (int i=1;i<=A[0];i++) sum-=a[a[A[i]].r].sum; for (int i=1;i<=B[0];i++) B[i]=a[B[i]].l; for (int i=1;i<=A[0];i++) A[i]=a[A[i]].l; r=mid; } else { for (int i=1;i<=B[0];i++) B[i]=a[B[i]].r; for (int i=1;i<=A[0];i++) A[i]=a[A[i]].r; l=mid+1; } } return sum; } inline LL ask_less(int l,int r,int num) { if (l>r) return 0;l--;A[0]=B[0]=0; for (int i=l;i;i-=L(i)) A[++A[0]]=root[i]; for (int i=r;i;i-=L(i)) B[++B[0]]=root[i]; l=1;r=n;LL sum=0; while (l!=r) { int mid=(l+r)>>1; if (num>mid) { for (int i=1;i<=B[0];i++) sum+=a[a[B[i]].l].sum; for (int i=1;i<=A[0];i++) sum-=a[a[A[i]].l].sum; for (int i=1;i<=B[0];i++) B[i]=a[B[i]].r; for (int i=1;i<=A[0];i++) A[i]=a[A[i]].r; l=mid+1; } else { for (int i=1;i<=B[0];i++) B[i]=a[B[i]].l; for (int i=1;i<=A[0];i++) A[i]=a[A[i]].l; r=mid; } } return sum; } inline void update(int &k,int l,int r) { if (!k) k=++node;a[k].sum++; if (l==r) return; int mid=(l+r)>>1; if (del<=mid) update(a[k].l,l,mid); else update(a[k].r,mid+1,r); } inline int Read() { char ch=getchar();for (;ch<'0'||ch>'9';ch=getchar()); int x=0;for (;ch>='0'&&ch<='9';ch=getchar()) x=x*10+ch-'0'; return x; } int main() { n=Read();m=Read(); for (i=1;i<=n;i++) { data[i]=Read();pos[data[i]]=i; ans+=(front[i]=i-1-ask(data[i]));up(data[i]); } memset(c,0,sizeof(c)); for (i=n;i;i--) back[i]=ask(data[i]-1),up(data[i]); for (i=1;i