http://www.lydsy.com/JudgeOnline/problem.php?id=3262
给定三维点对(xi,yi,zi)若两个点对存在xi<=xj,yi<=yj,zi<=zj则称点i<j,询问每个点前有多少点
三维偏序
cdq分治
我们对三维按x为第一关键字,y为第二关键字.z为第三关键字排序
这样我们得到的每个点前面的点x那维一定小于等于自己
然后我们分治y那维,这个过程类似归并排序的过程
对于我们分治时相邻的区间,我们把两个区间内的点只看y那维合并成一个区间
对于左边的区间会对右边区间产生贡献(因为x值<=右边的任意一个)
这个贡献我们把他们的z值插进树状数组中
当右区间指针的点因为比左区间指针的点而踢出时,查询树状数组中小于等于它z值得点个数
这样就可以优化掉一位
不清楚的画图看看,注意相同的先和成一个点,插进树状数组时是sum值不是1,每次树状数组要清0
type
data=record
x,y,z,num,ans:longint; end;
var
t,temp:array[0..100005]of data;
bite,ans:array[0..200005]of longint;
i,j,k:longint;
n,m,s:longint;
procedure sort(l,r:longint);
var i,j,a,b,c:longint; d:data;
begin
i:=l; j:=r; a:=t[(l+r) div 2].x; b:=t[(l+r)div 2].y; c:=t[(l+r)div 2].z;
repeat
while (t[i].x<a)or((t[i].x=a)and(t[i].y<b))or((t[i].x=a)and(t[i].y=b)and(t[i].z<c)) do inc(i);
while (a<t[j].x)or((t[j].x=a)and(t[j].y>b))or((t[j].x=a)and(t[j].y=b)and(t[j].z>c)) do dec(j);
if not(i>j) then
begin
d:=t[i]; t[i]:=t[j]; t[j]:=d;
inc(i); dec(j);
end;
until i>j;
if l<j then sort(l,j);
if i<r then sort(i,r);
end;
procedure update(a,b:longint);
var tt:longint;
begin
tt:=a;
while tt<=s do
begin
inc(bite[tt],b);
inc(tt,tt and (-tt));
end;
end;
function query(a:longint):longint;
var tt,sum:longint;
begin
tt:=a; sum:=0;
while tt>0 do
begin
inc(sum,bite[tt]);
dec(tt,tt and (-tt));
end;
exit(sum);
end;
procedure cdq(l,r:longint);
var i,j,k,mid,len:longint;
begin
if l=r then exit;
mid:=(l+r)>>1;
cdq(l,mid); cdq(mid+1,r);
i:=l; j:=mid+1; len:=l;
while (i<=mid)and(j<=r) do
begin
if (t[i].y<=t[j].y)
then begin update(t[i].z,t[i].num); temp[len]:=t[i]; inc(i); inc(len); continue; end
else begin inc(t[j].ans,query(t[j].z)); temp[len]:=t[j]; inc(j); inc(len); end;
end;
for k:=j to r do
begin inc(t[k].ans,query(t[k].z)); temp[len]:=t[k]; inc(len); end;
for k:=l to mid do
if k>=i
then begin temp[len]:=t[k]; inc(len); end
else update(t[k].z,-t[k].num);
for i:=l to r do
t[i]:=temp[i];
end;
begin
readln(n,s);
for i:=1 to n do
readln(t[i].x,t[i].y,t[i].z);
sort(1,n); {t[i].x}
m:=0; t[0].x:=0; t[0].y:=0; t[0].z:=0;
for i:=1 to n do
begin t[i].ans:=0; t[i].num:=0; end;
for i:=1 to n do
if (t[i].x=t[i-1].x)and(t[i].y=t[i-1].y)and(t[i].z=t[i-1].z)
then inc(t[m].num)
else begin inc(m); t[m]:=t[i]; t[m].num:=1; end;
cdq(1,m);
fillchar(ans,sizeof(ans),0);
for i:=1 to n do
inc(ans[t[i].ans+t[i].num-1],t[i].num);
for i:=0 to n-1 do
writeln(ans[i]);
end.