链接:http://acm.hdu.edu.cn/showproblem.php?pid=5324
题意:t组数据,每组给出一个n,然后跟着n个点,每个点都有三个值x,y,z,最后输出对于每个点比它三维小于等于的点有多少个。
思路:是一道先一维排序再cdq+树状数组解决三维偏序的入门题,先对x排序,再对y层次cdq分治,对z的排序运用树状数组求逆序对的方式。
代码很长但是感觉思路还是很清晰的,写着有一种蛮舒服的感觉= =
AC代码:
#include<bits/stdc++.h>
#define INF 0x3F3F3F3F
#define endl '\n'
#define pb push_back
#define css(n) cout<<setiosflags(ios::fixed)<<setprecision(n);
#define sd(a) scanf("%d",&a)
#define sld(a) scanf("%lld",&a)
#define m(a,b) memset(a,b,sizeof a)
#define p_queue priority_queue
using namespace std;
typedef long long ll;
const int maxn=100005;
int n,m;
int t;
double a,b;
int N;
int tre[maxn];
struct node
{
int x,y,z;
int sum;
int id;
}dian[maxn];
int fin[maxn];
bool comp1(node a,node b)
{
if(a.x!=b.x) return a.x<b.x;
else
{
if(a.y!=b.y) return a.y<b.y;
else return a.z<b.z;
}
}
bool comp2(node a,node b)
{
return a.y<b.y;
}
int lowbit(int x)
{
return x&(-x);
}
void add(int pos,int val)
{
while(pos<=N)
{
tre[pos]+=val;
pos+=lowbit(pos);
}
}
int ask(int x)
{
int ans=0;
while(x)
{
ans+=tre[x];
x=x-lowbit(x);
}
return ans;
}
void cdq(int l,int r)
{
if(l==r) return;
int mid=(l+r)>>1;
cdq(l,mid),cdq(mid+1,r);//cdq分治,一层一层的分下去,类似于线段树一样。
sort(dian+l,dian+mid+1,comp2);
sort(dian+mid+1,dian+r+1,comp2);//对左边和右边的y排序。
int j=l;
for(int i=mid+1;i<=r;i++)
{
for(;j<=mid&&dian[j].y<=dian[i].y;j++)
{
// if(dian[j].y<=dian[i].y)
add(dian[j].z,1);//满足左边比右边的y小时就把z加入到树状数组。
//只要一次j不满足就直接break掉,因为后面的j都比这个j大,也不可能满足小于关系。
// else break;
}
dian[i].sum+=ask(dian[i].z);
// cout<<dian[i].id<<"--"<<dian[i].sum<<endl;
}
for(j=j-1;j>=l;j--)
{
add(dian[j].z,-1);
}
//将j前面加过的树状数组的值还原。
}
int main()
{
sd(t);
while(t--)
{
memset(tre,0,sizeof(tre));
sd(n);
N=0;
for(int i=1;i<=n;i++)
{
scanf("%d%d%d",&dian[i].x,&dian[i].y,&dian[i].z);
dian[i].sum=0;
dian[i].id=i;
N=max(N,dian[i].z);//树状数组的最大值应该是所有点中z最大的那个值,不优化的话就直接写maxn-1也行,优化后发现也就快了几十ms。。
}
sort(dian+1,dian+1+n,comp1);
/* for(int i=1;i<=n;i++)
{
cout<<dian[i].id<<endl;
}*/
cdq(1,n);
for(int i=1;i<=n;)
{
int j=i+1;
int mx=dian[i].sum;
for(;j<=n&&dian[i].x==dian[j].x&&dian[i].y==dian[j].y&&dian[i].z==dian[j].z;j++)
{
mx=max(mx,dian[j].sum);
}
for(int k=i;k<j;k++)
{
fin[dian[k].id]=mx;
}
i=j;
}
for(int i=1;i<=n;i++)
{
printf("%d\n",fin[i]);
}
}
return 0;
}
修改之后的代码:
解决问题应该是没错的,但是会t掉,,,我也不知道为什么,可能bug不是在去重那儿吗。。。
#include<bits/stdc++.h>
#define INF 0x3F3F3F3F
#define endl '\n'
#define pb push_back
#define css(n) cout<<setiosflags(ios::fixed)<<setprecision(n);
#define sd(a) scanf("%d",&a)
#define sld(a) scanf("%lld",&a)
#define m(a,b) memset(a,b,sizeof a)
#define p_queue priority_queue
using namespace std;
typedef long long ll;
const int maxn=100005;
int n,m;
int t;
double a,b;
int N;
int n1;
int tre[maxn];
struct node
{
int x,y,z;
int sum;
int id;
int num;
vector<int> ids;
}dian[maxn],p1[maxn];
int fin[maxn];
bool comp1(node a,node b)
{
if(a.x!=b.x) return a.x<b.x;
else
{
if(a.y!=b.y) return a.y<b.y;
else return a.z<b.z;
}
}
bool comp2(node a,node b)
{
return a.y<b.y;
}
int lowbit(int x)
{
return x&(-x);
}
void add(int pos,int val)
{
while(pos<=N)
{
tre[pos]+=val;
pos+=lowbit(pos);
}
}
int ask(int x)
{
int ans=0;
while(x)
{
ans+=tre[x];
x=x-lowbit(x);
}
return ans;
}
void cdq(int l,int r)
{
if(l==r) return;
int mid=(l+r)>>1;
cdq(l,mid),cdq(mid+1,r);//cdq分治,一层一层的分下去,类似于线段树一样。
sort(p1+l,p1+mid+1,comp2);
sort(p1+mid+1,p1+r+1,comp2);//对左边和右边的y排序。
int j=l;
for(int i=mid+1;i<=r;i++)
{
for(;j<=mid&&p1[j].y<=p1[i].y;j++)
{
// if(dian[j].y<=dian[i].y)
add(p1[j].z,p1[j].num);//满足左边比右边的y小时就把z加入到树状数组。
//只要一次j不满足就直接break掉,因为后面的j都比这个j大,也不可能满足小于关系。
// else break;
}
p1[i].sum+=ask(p1[i].z);
// cout<<dian[i].id<<"--"<<dian[i].sum<<endl;
}
for(j=j-1;j>=l;j--)
{
add(p1[j].z,-p1[j].num);
}
//将j前面加过的树状数组的值还原。
}
int main()
{
sd(t);
while(t--)
{
memset(tre,0,sizeof(tre));
sd(n);
N=0;
for(int i=1;i<=n;i++)
{
scanf("%d%d%d",&dian[i].x,&dian[i].y,&dian[i].z);
dian[i].sum=0;
dian[i].id=i;
dian[i].num=1;
N=max(N,dian[i].z);//树状数组的最大值应该是所有点中z最大的那个值,不优化的话就直接写maxn-1也行,优化后发现也就快了几十ms。。
}
sort(dian+1,dian+1+n,comp1);
int i=1;
n1=0;
while(i<=n)
{
p1[++n1]=dian[i];
p1[n1].ids.pb(dian[i].id);
int j=i+1;
while(j<=n)
{
if(dian[j].x==dian[i].x&&dian[j].y==dian[i].y&&dian[j].z==dian[i].z)
{
p1[n1].ids.pb(dian[j].id);
j++;
p1[n1].num++;
}
else break;
}
i=j;
}
cdq(1,n1);
/* for(int i=1;i<=n;)
{
int j=i+1;
int mx=dian[i].sum;
for(;j<=n&&dian[i].x==dian[j].x&&dian[i].y==dian[j].y&&dian[i].z==dian[j].z;j++)
{
mx=max(mx,dian[j].sum);
}
for(int k=i;k<j;k++)
{
fin[dian[k].id]=mx;
}
i=j;
}*/
for(int i=1;i<=n1;i++)
{
int len=p1[i].ids.size();
for(int j=0;j<len;j++)
{
int zz=p1[i].ids[j];
fin[zz]=p1[i].sum+p1[i].num-1;
}
}
for(int i=1;i<=n;i++)
{
printf("%d\n",fin[i]);
}
}
return 0;
}