質問の意味:
所与\(N- \)要素、各要素は、4つの属性があり、\(A、B、C、Dを\)を満たすこと配列を求めて、\(a_iを<a_j \)と\(b_i <b_j \)と\ (C_I <c_j \)と\(D_I <d_j \)の数\((i、j)は\ ) 番号。
以下のための\(100%\)データ、\(1 <= N - <= 50000 \) 、全てのことを確実にする\(BI、AI、CI、ジ\)は4つにグループ化されている\(1 \) 〜\(N- \ )配置。
アイデア:
最初の次元の並べ替え。
(この要素を更新することができ、または他の要素が更新されてもよいかどうかかどうか、すなわち、)第二次元CDQパーティションは、順序付けられた維持しながら、第二の寸法は、一次元の記録順序は、
CDQパーティションを続ける三次元で、三次元は維持しています順
フェンウィックツリーメンテナンス統計の答えと上記の前提で四次元、
注意事項:
無効な手を用心
コード:
#include<bits/stdc++.h>
using namespace std;
const int N=50005;
int n,ans;
struct node{int a,b,c,d,tp;}q[N],tmp1[N],tmp2[N];
inline bool cmp1(node x,node y){return x.a<y.a;}
inline int read()
{
int s=0,w=1; char ch=getchar();
for(;!isdigit(ch);ch=getchar())if(ch=='-')w=-1;
for(;isdigit(ch);ch=getchar())s=(s<<1)+(s<<3)+(ch^48);
return s*w;
}
struct tree{
int cc[N];
inline int lowbit(int x){return x&(-x);}
inline void add(int x,int v)
{
for(;x<=n;x+=lowbit(x))cc[x]+=v;
}
inline int query(int x)
{
int anss=0;
for(;x;x-=lowbit(x))anss+=cc[x];
return anss;
}
}T;
void cdq3d(int l,int r)
{
if(l==r) return;
int mid=l+r>>1;
cdq3d(l,mid);cdq3d(mid+1,r);
int i=l,j=mid+1,cnt2=l;
while(j<=r)
{
while(tmp1[i].c<tmp1[j].c&&i<=mid)
{
if(tmp1[i].tp==1) T.add(tmp1[i].d,1);
tmp2[cnt2++]=tmp1[i++];
}
if(tmp1[j].tp==2) ans+=T.query(tmp1[j].d);
tmp2[cnt2++]=tmp1[j++];
}
for(int e=l;e<i;++e)
if(tmp1[e].tp==1) T.add(tmp1[e].d,-1);
for(int e=i;e<=mid;++e) tmp2[cnt2++]=tmp1[e];
for(int e=l;e<=r;++e) tmp1[e]=tmp2[e];
}
void cdq2d(int l,int r)
{
if(l==r) return;
int mid=l+r>>1;
cdq2d(l,mid);cdq2d(mid+1,r);
int i=l,j=mid+1,cnt1=l;
while(j<=r)
{
while(q[i].b<q[j].b&&i<=mid) q[i].tp=1,tmp1[cnt1++]=q[i++];
q[j].tp=2,tmp1[cnt1++]=q[j++];
}
for(int e=i;e<=mid;++e) q[e].tp=1,tmp1[cnt1++]=q[e];
for(int e=l;e<=r;++e) q[e]=tmp1[e];
cdq3d(l,r);
}
int main()
{
n=read();
for(int i=1;i<=n;++i)q[i].a=read();
for(int i=1;i<=n;++i)q[i].b=read();
for(int i=1;i<=n;++i)q[i].c=read();
for(int i=1;i<=n;++i)q[i].d=read();
sort(q+1,q+n+1,cmp1);
cdq2d(1,n);
cout<<ans;
return 0;
}