\ [\ texttt {説明} \]
長さの2つの\(N- \)シーケンス\(A \)と\(B \) 、満足しよう\(a_iを+ a_j> b_i + b_j \(I <J)\) 数の対数を。
\ [\ Texttt {解決} \ ]
- まず、双方は、この式も登場留意(I、J \)\互いに独立していない式の両側に言うことです。
- ああ、自然に考え移調大法は、式がに減少させることができる(a_iを-b_i> b_j-a_j \(I <J)\)\。側式であった\(I \)しばらくの間、\(J \) 、それは式の両側に互いに独立しているように、。
私たちは、この半順序の問題を行うにはあまりにも良いだけではなく、発見しましたこの問題は半順序を解決するために多くの方法がありますが、ここで提示ダイナミック処方重量セグメントツリーアプローチを。- 逆の順序でスキャン\(N- \)スイープ\(1 \) 。
- セグメントツリーの重量範囲\ - ([\ INF、a_iを -b_i-1] \) 回答に含まれる値の数。
- 順番にセグメント重みツリー\(b_i-a_iを\)プラス数a。
- 時間計算\(\ mathcal {O(N- \)N-ログ} \) 、空間複雑\(O(N \ログサイズ)\)離散化があれば何ができるか、\(O(N Nログ\ ) \) 。
\ [\ texttt {コード} \]
#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;
}
\ [\ texttt {ありがとう} \ \ texttt \ \ \ texttt {見} {用}]