給兩個長度爲 \(n\) 的序列 \(a\) 和 \(b\) ,求知足 \(a_i+a_j>b_i+b_j \ (i<j)\) 的數對個數。c++
首先注意到這個式子左右兩邊同時出現了 \(i,j\) ,也就是說式子兩邊不是互相獨立的。spa
嗯,天然地想到了移項大法,式子能夠化爲 \(a_i-b_i>b_j-a_j \ (i<j)\) 。式子的一邊爲 \(i\) ,一邊爲 \(j\) ,就使得式子兩邊互相獨立。code
咱們發現這個偏序問題簡直不要太好作,有不少的方法能夠解決這個偏序問題,這裏介紹一種 動態開點權值線段樹 的作法。ip
倒序掃描,從 \(n\) 掃到 $1$ 。get
時間複雜度 \(\mathcal{O(n \log n)}\) ,空間複雜度 \(O(n \log size)\) ,若是離散化一下能夠作到 \(O(n \log n)\) 。io
#include<cstdio> #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=200100,MLOGN=10001000; int n; int a[N],b[N]; const int INF=2e9; int tot,root; struct SegmentTree{ int lc,rc; int cnt; }t[MLOGN]; 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 val) { if(!p) p=New(); t[p].cnt+=val; if(l==r)return; int mid=(long long)(l+r)>>1; if(delta<=mid) insert(t[p].lc,l,mid,delta,val); else insert(t[p].rc,mid+1,r,delta,val); } int ask(int p,int l,int r,int s,int e) { if(!p) return 0; if(s<=l&&r<=e) return t[p].cnt; int mid=(long long)(l+r)>>1; int val=0; if(s<=mid) val+=ask(t[p].lc,l,mid,s,e); if(mid<e) val+=ask(t[p].rc,mid+1,r,s,e); return val; } long long ans; int main() { n=read(); for(RI i=1;i<=n;i++) a[i]=read(); for(RI i=1;i<=n;i++) b[i]=read(); for(RI i=n;i>=1;i--) { ans+=ask(root,-INF,INF,-INF,a[i]-b[i]-1); insert(root,-INF,INF,b[i]-a[i],1); } printf("%lld\n",ans); return 0; }