COGS 2580. [HZOI 2015]偏序 II
题目传送门
题目大意:给n个元素,每个元素有具有4个属性a,b,c,d,求i<j并且ai<aj,bi<bj,ci<cj,di<dj的i,j对数有多少?
a,b,c,d均为1~n的排列,即不会有i,j使得ai=aj or bi=bj or ci=cj or di=dj。
题目是离线的,cdq分治可以很好的解决这一类问题。cdq套cdq套cdq再加个bit就行了。
第一层的cdq处理a,保证a有序,
第二层在第一层的基础上处理b,保证b有序,以此类推。
第三层最后处理d,将添加的加进bit,询问的查询1~d有多少个,累加进答案ans,最后反过来删掉加进去的。(相当于清空bit)
我写的是指针形的,代码会比较短……
#include<cstdio>
#include<algorithm>
using namespace std;
const int N=50050;
struct data { int a,b,c,d,id; bool p; } D[4][N];
int n,px,T[N],ans;
bool cmp(data A,data B)
{
if(px==1) return (A.a<B.a); else
if(px==2) return (A.b<B.b); else
if(px==3) return (A.c<B.c);
}
void add(int x,int v) { for(int i=x;i<=n;i+=(i&-i)) T[i]+=v; }
int sum(int x) { int Ans=0; for(int i=x;i;i-=(i&-i)) Ans+=T[i]; return Ans; }
void CDQ(int now,int L,int R)
{
if(L==R) return;
int Mid=(L+R)>>1; data *S=D[now+1],*F=D[now];
int s=0;
if(now==0)
{
for(int i=L;i<=Mid;i++) S[++s]=F[i],S[s].p=0;
for(int i=Mid+1;i<=R;i++) S[++s]=F[i],S[s].p=1;
} else
{
for(int i=L;i<=Mid;i++) if(!F[i].p) S[++s]=F[i];
for(int i=Mid+1;i<=R;i++) if(F[i].p) S[++s]=F[i];
}
if(s)
{
px=now+1; sort(S+1,S+1+s,cmp);
if(now==2)
{
for(int i=1;i<=s;i++)
if(!S[i].p) add(S[i].d,1); else ans+=sum(S[i].d);
for(int i=1;i<=s;i++)
if(!S[i].p) add(S[i].d,-1);
} else CDQ(now+1,1,s);
}
CDQ(now,L,Mid); CDQ(now,Mid+1,R);
}
int main()
{
freopen("partial_order_two.in","r",stdin);
freopen("partial_order_two.out","w",stdout);
scanf("%d",&n); data *F=D[0];
for(int i=1;i<=n;i++) F[i].id=i;
for(int i=1;i<=n;i++) scanf("%d",&F[i].a);
for(int i=1;i<=n;i++) scanf("%d",&F[i].b);
for(int i=1;i<=n;i++) scanf("%d",&F[i].c);
for(int i=1;i<=n;i++) scanf("%d",&F[i].d);
ans=0; CDQ(0,1,n);
printf("%d\n",ans);
return 0;
}