\[ \texttt{Description} \]spa
給兩個長度爲 \(n\) 的數列 \(A\) 和 \(B\) 。code
記 \(A\) 的逆序對(知足 \(x<y\),\(A_x>A_y\) 的數對 \((x,y)\) )對答案的貢獻爲 \(B_x+B_y\) 。ip
通俗地說,答案就是 \(\sum\limits_{x < y \ \& \ A_x > A_y}\) \(B_x+B_y\)。get
一共 \(m\) 次交換,每次交換 \(A_x\) 和 \(A_y\) ,\(B_x\) 和 \(B_y\) 。it
每次交換後,你都要給出答案。
\[ \texttt{Solution} \]io
首先,對於初始序列的答案,顯然能夠用兩個 \(\text{BIT}\) 來作,一個 \(\text{BIT}\) 維護值域內數的數量,一個 \(\text{BIT}\) 維護值域內數的 \(B\) 值和 ,像 \(\text{BIT}\) 求逆序對同樣地,從後往前掃,考慮當前位置 \(x\) 上的數 \(A_x\) ,與 \(x+1\) 到 \(n\) 之間的 \(A_y\) 產生的逆序對對答案的貢獻,記 \(C_1\) 爲 \(A\) 值在 \([1,A_x-1]\) 內數的個數,記 \(C_2\) 爲 \(A\) 值在 \([1,A_x-1]\) 內數的 \(B\) 值和,則對答案的貢獻有 \(B_x \times C_1+C_2\) ,求完整個序列的答案的複雜度是 \(\mathcal{O(n \log n)}\) 的。class
首先,交換 \(x,y\) 顯然不會影響到 \([1,x-1]\) 和 \([y+1,n]\) 中的數與 \(A_x\) 或 \(A_y\) 產生的逆序對,由於相對位置是不變的。再者,對於 \(A_x\) 和 \(A_y\) 是否會造成逆序對,能夠直接討論一下 \(A_x\) 和 \(A_y\) 的大小關係。gc
因而咱們只要考慮 \([x+1,y-1]\) 內的數與 \(A_x\) 和 \(A_y\) 的逆序對關係,咱們能夠視交換 \(x,y\) 爲:在 \(x\) 處除去一個 \(A_x\) ,在 \(x\) 處增上一個 \(A_y\) ,在 \(y\) 處除去一個 \(A_y\) ,在 \(y\) 處增上一個 \(A_x\) 。im
那麼答案的變化應該爲:查詢
減去 " \(B_x\times\) 區間 \([x+1,y-1]\) 內 \(A\) 值在 \([1,A_x-1]\) 的數的個數 \(+\) 區間 \([x+1,y-1]\) 內 \(A\) 值在 \([1,A_x-1]\) 的數的 \(B\) 值和 " 。
加上 " \(B_y\times\) 區間 \([x+1,y-1]\) 內 \(A\) 值在 \([1,A_y-1]\) 的數的個數 \(+\) 區間 \([x+1,y-1]\) 內 \(A\) 值在 \([1,A_y-1]\) 的數的 \(B\) 值和 " 。
減去 " \(B_y\times\) 區間 \([x+1,y-1]\) 內 \(A\) 值在 \([A_y+1,n]\) 的數的個數 \(+\) 區間 \([x+1,y-1]\) 內 \(A\) 值在 \([A_y+1,n]\) 的數的 \(B\) 值和 " 。
加上 " \(B_x\times\) 區間 \([x+1,y-1]\) 內 \(A\) 值在 \([A_x+1,n]\) 的數的個數 \(+\) 區間 \([x+1,y-1]\) 內 \(A\) 值在\([A_x+1,n]\) 的數的 \(B\) 值和 " 。
\(\mathcal{O(n \log^2 n)}\) ,評測記錄 。
\[ \texttt{Code} \]
#include<cstdio> #include<algorithm> #define RI register int using namespace std; namespace IO { static char buf[1<<20],*fs,*ft; inline char gc() { if(fs==ft) { ft=(fs=buf)+fread(buf,1,1<<20,stdin); if(fs==ft)return EOF; } return *fs++; } #define gc() getchar() inline int read() { int x=0,f=1;char s=gc(); while(s<'0'||s>'9'){if(s=='-')f=-f;s=gc();} while(s>='0'&&s<='9'){x=x*10+s-'0';s=gc();} return x*f; } }using IO::read; const int N=50100,MLOGNLOGN=20000000; const int Mod=1e9+7; void ckadd(long long &x,long long val) { x=((x+val)%Mod+Mod)%Mod; } int n,m; long long a[N],b[N]; long long BIT[N][2]; // 0 個數 : 1 和 void BIT_add(int x,int k,int val) { for(;x<=n;x+=x&-x)ckadd(BIT[x][k],val); } long long BIT_ask(int x,int k) { long long ans=0; for(;x;x-=x&-x)ckadd(ans,BIT[x][k]); return ans; } long long ans; int tot,root[N]; struct SegmentTree{ int lc,rc; long long cnt; long long sum; }t[MLOGNLOGN]; int New() { tot++; t[tot].lc=t[tot].rc=t[tot].cnt=0; return tot; } void insert(int &p,int l,int r,int delta,int cnt,int sum) { if(!p)p=New(); ckadd(t[p].cnt,cnt); ckadd(t[p].sum,sum); if(l==r)return; int mid=(l+r)/2; if(delta<=mid) insert(t[p].lc,l,mid,delta,cnt,sum); else insert(t[p].rc,mid+1,r,delta,cnt,sum); } void add(int pos,int delta,int cnt,int sum) { for(;pos<=n;pos+=pos&-pos) insert(root[pos],1,n,delta,cnt,sum); } int lenA,addt[N]; int lenS,subt[N]; long long ask(int L,int R,int k,int s,int e) // 區間 [l,r] 類型 k 值域 [s,e] { if(e==0||s>e) return 0; long long res=0; int l,r; lenA=0; for(RI i=R;i;i-=i&-i)addt[++lenA]=root[i]; lenS=0; for(RI i=L-1;i;i-=i&-i)subt[++lenS]=root[i]; l=1,r=n; while(true) { if(l==r) { for(RI i=1;i<=lenA;i++)ckadd(res,k?t[addt[i]].sum:t[addt[i]].cnt); for(RI i=1;i<=lenS;i++)ckadd(res,k?-t[subt[i]].sum:-t[subt[i]].cnt); break; } int mid=(l+r)/2; if(e<=mid) { for(RI i=1;i<=lenA;i++)addt[i]=t[addt[i]].lc; for(RI i=1;i<=lenS;i++)subt[i]=t[subt[i]].lc; r=mid; } else { for(RI i=1;i<=lenA;i++)ckadd(res,k?t[t[addt[i]].lc].sum:t[t[addt[i]].lc].cnt); for(RI i=1;i<=lenS;i++)ckadd(res,k?-t[t[subt[i]].lc].sum:-t[t[subt[i]].lc].cnt); for(RI i=1;i<=lenA;i++)addt[i]=t[addt[i]].rc; for(RI i=1;i<=lenS;i++)subt[i]=t[subt[i]].rc; l=mid+1; } } if(s==1) return res; lenA=0; for(RI i=R;i;i-=i&-i)addt[++lenA]=root[i]; lenS=0; for(RI i=L-1;i;i-=i&-i)subt[++lenS]=root[i]; l=1,r=n; while(true) { if(l==r) { for(RI i=1;i<=lenA;i++)ckadd(res,k?-t[addt[i]].sum:-t[addt[i]].cnt); for(RI i=1;i<=lenS;i++)ckadd(res,k?t[subt[i]].sum:t[subt[i]].cnt); break; } int mid=(l+r)/2; if(s-1<=mid) { for(RI i=1;i<=lenA;i++)addt[i]=t[addt[i]].lc; for(RI i=1;i<=lenS;i++)subt[i]=t[subt[i]].lc; r=mid; } else { for(RI i=1;i<=lenA;i++)ckadd(res,k?-t[t[addt[i]].lc].sum:-t[t[addt[i]].lc].cnt); for(RI i=1;i<=lenS;i++)ckadd(res,k?t[t[subt[i]].lc].sum:t[t[subt[i]].lc].cnt); for(RI i=1;i<=lenA;i++)addt[i]=t[addt[i]].rc; for(RI i=1;i<=lenS;i++)subt[i]=t[subt[i]].rc; l=mid+1; } } return res; } void turn(int x,int y) { if(x>y) swap(x,y); if(x+1<=y-1) { ckadd(ans,-b[x]*ask(x+1,y-1,0,1,a[x]-1)-ask(x+1,y-1,1,1,a[x]-1)); ckadd(ans,-b[y]*ask(x+1,y-1,0,a[y]+1,n)-ask(x+1,y-1,1,a[y]+1,n)); ckadd(ans,b[y]*ask(x+1,y-1,0,1,a[y]-1)+ask(x+1,y-1,1,1,a[y]-1)); ckadd(ans,b[x]*ask(x+1,y-1,0,a[x]+1,n)+ask(x+1,y-1,1,a[x]+1,n)); } if(a[x]>a[y]) ckadd(ans,-b[x]-b[y]); else if(a[x]<a[y]) ckadd(ans,b[x]+b[y]); add(x,a[x],-1,-b[x]); add(y,a[y],-1,-b[y]); swap(a[x],a[y]),swap(b[x],b[y]); add(x,a[x],1,b[x]); add(y,a[y],1,b[y]); } int main() { n=read(),m=read(); for(RI i=1;i<=n;i++) a[i]=read(),b[i]=read(), add(i,a[i],1,b[i]); for(RI i=n;i;i--) { ckadd(ans,b[i]*BIT_ask(a[i]-1,0)+BIT_ask(a[i]-1,1)); BIT_add(a[i],0,1),BIT_add(a[i],1,b[i]); } while(m--) { int x=read(),y=read(); turn(x,y); printf("%lld\n",ans); } return 0; }
\[ \texttt{Thanks} \ \texttt{for} \ \texttt{watching} \]