Jam's problem again
Time Limit: 5000/2500 MS (Java/Others) Memory Limit: 65536/65536 K (Java/Others)
Total Submission(s): 1583 Accepted Submission(s): 573
Total Submission(s): 1583 Accepted Submission(s): 573
Problem Description
Jam like to solve the problem which on the 3D-axis,given
N(1≤N≤100000)
points
(x,y,z)(1≤x,y,z≤100000)
If two point such as (xi,yi,zi) and (xj,yj,zj) xi≥xj yi≥yj zi≥zj , the bigger one level add 1
Ask for the each level of the point.
If two point such as (xi,yi,zi) and (xj,yj,zj) xi≥xj yi≥yj zi≥zj , the bigger one level add 1
Ask for the each level of the point.
Input
The first line is
T(1≤T≤15)
means
T
Case
For each case
The first line is N means the number of Point and next there are N line, each line has (x,y,z)
For each case
The first line is N means the number of Point and next there are N line, each line has (x,y,z)
Output
Output with N line,each line has one number means the lever of point
Sample Input
1 4 10 4 7 10 6 6 8 2 5 7 3 10
Sample Output
1 1 0 0
题意:略 ;
思路: cdq分治:
1. 先把各点按 x 坐标升序排序。
2. 并把所有点分为2部分:1 - mid(前半部分) , mid+1 - n(后半部分)。
3. 再把所有点按y坐标升序排序。
4. 遍历所有点,若该点为前半部分的点,则将它的z坐标插入到树状数组中,若为后半部分的点,则查询该点z坐标在树状数组中的值。遍历完毕后清空树状数组。
递归:将1 - mid(前半部分)重复2-4步骤,1 - mid(前半部分)也重复2-4步骤。
PS:要特殊考虑完全一样的点。
#include <iostream>
#include <cstdio>
#include <cstring>
#include <cmath>
#include <queue>
#include <vector>
#include <algorithm>
using namespace std;
const int MAX = 100000+9;
typedef struct{
int x,y,z;
int id; //原点集中的下标
}Point;
Point a[MAX],b[MAX];
int c[MAX];
long long ans[MAX];
//一定要写完整,不然会wa
bool cmpx(Point s1,Point s2)
{
if(s1.x==s2.x)
{
if(s1.y==s2.y)
{
if(s1.z==s2.z)
return s1.id<s2.id;
else
return s1.z<s2.z;
}
else
return s1.y<s2.y;
}
return s1.x<s2.x;
}
bool cmpy(Point s1,Point s2)
{
if(s1.y==s2.y)
return s1.z<s2.z;
return s1.y<s2.y;
}
//树状数组操作---------------
int lowbit(int x)
{
return x&(-x);
}
//添加add
void add(int k,int x)
{
while(k<=MAX)
{
c[k]+=x;
k+=lowbit(k);
}
}
//查询query
int sum(int x)
{
int sum=0;
while(x>0)
{
sum+=c[x];
x-=lowbit(x);
}
return sum;
}
//------------------------------------
void solve(int l,int r)
{
if(l>=r)
return;
int mid=(l+r)/2;
int cnt=0;
//标记为前半部分
for(int i=l;i<=mid;i++)
{
cnt++;
b[cnt].x=0;
b[cnt].y=a[i].y;
b[cnt].z=a[i].z;
b[cnt].id=-1;
}
//标记为后半部分
for(int i=mid+1;i<=r;i++)
{
cnt++;
b[cnt].x=0;
b[cnt].y=a[i].y;
b[cnt].z=a[i].z;
b[cnt].id=a[i].id;
}
//按y坐标排序
sort(b+1,b+cnt+1,cmpy);
for(int i=1;i<=cnt;i++)
{
//若为前半部分,插入到树状数组
if(b[i].id==-1)
{
add(b[i].z,1);
}
//若为后半部分,在树状数组中搜索
else
{
ans[b[i].id]+=sum(b[i].z);
}
}
//清空树状数组
for(int i=1;i<=cnt;i++)
{
if(b[i].id==-1)
{
add(b[i].z,-1);
}
}
//递归
solve(l,mid);
solve(mid+1,r);
}
int main()
{
int T;
scanf("%d",&T);
while(T--)
{
memset(c,0,sizeof(c));
memset(ans,0,sizeof(ans));
int n;
scanf("%d",&n);
for(int i=1;i<=n;i++)
{
scanf("%d%d%d",&a[i].x,&a[i].y,&a[i].z);
a[i].id=i;
}
//按x坐标排序
sort(a+1,a+n+1,cmpx);
//考虑两个坐标完全相同的情况
int res=0;
for(int i=n-1;i>=1;i--)
{
if(a[i].x==a[i+1].x&&a[i].y==a[i+1].y&&a[i].z==a[i+1].z)
{
res++;
}
else
res=0;
ans[a[i].id]+=res;
}
//cdq分治
solve(1,n);
for(int i=1;i<=n;i++)
{
printf("%lld\n",ans[i]);
}
}
return 0;
}