题目链接:http://acm.neu.edu.cn/hustoj/problem.php?id=1702
题目大意:就是问每个人三个属性同时不低于另外几个人。。。。人不分先后
经典的三维偏序问题
解题思路:CDQ分治练手题
#include<cstdio>
#include<vector>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
int const MAX_Z=+;
int const MAX_N=+;
struct Ope{
int x,y,z;
int ty,id;
Ope(int x,int y,int z,int ty,int id):x(x),y(y),z(z),ty(ty),id(id){}
Ope(){}
}; bool cmp_x(Ope a,Ope b){
if(a.x==b.x)return a.ty<b.ty;
return a.x<b.x;
}
bool cmp_y(Ope a,Ope b){
if(a.y==b.y)return a.ty<b.ty;
return a.y<b.y;
} vector<Ope> ope,ope2;
//vector<int> allZ;
vector<int>::iterator it;
int tree[MAX_Z];
int ans[MAX_Z];
void add(int x,int a){
while(x<MAX_Z){
tree[x]+=a;
x+=(x&(-x));
}
} int read(int x){
int sum=;
while(x){
sum+=tree[x];
x-=(x&(-x));
}
return sum;
} void work(){
for(int i=;i<ope2.size();i++){
if(ope2[i].ty==) add(ope2[i].z,);
else{
int temp=read(ope2[i].z);
ans[ope2[i].id]+=temp*ope2[i].ty;
}
}
for(int i=;i<ope2.size();i++)
if(ope2[i].ty==) add(ope2[i].z,-); } void CDQ(int L,int R){
if(L>=R)return;
int mid=(L+R)>>;
CDQ(L,mid);
ope2.clear();
for(int i=L;i<=mid;i++){
if(ope[i].ty==)
ope2.push_back(ope[i]);
}
for(int i=mid+;i<=R;i++){
if(ope[i].ty!=)
ope2.push_back(ope[i]);
}
sort(ope2.begin(),ope2.end(),cmp_y);
work();
CDQ(mid+,R);
} int main(){
int T;
int n;
scanf("%d",&T);
while(T--){
scanf("%d",&n);
ope.clear();
//allZ.clear();
memset(tree,,sizeof(tree));
memset(ans,,sizeof(ans));
for(int i=;i<=n;i++){
int x,y,z;
scanf("%d%d%d",&x,&y,&z);
ope.push_back(Ope(x,y,z,,i));
ope.push_back(Ope(x,y,z,,i));
//allZ.push_back(z);
}
/*
sort(allZ.begin(),allZ.end());
it=unique(allZ.begin(),allZ.end());
allZ.resize(distance(allZ.begin(),it));
for(int i=0;i<ope.size();i++){
ope[i].z=lower_bound(allZ.begin(),allZ.end(),ope[i].z)-allZ.begin()+1;
}
*/
sort(ope.begin(),ope.end(),cmp_x);
CDQ(,ope.size()-);
for(int i=;i<=n;i++){
printf("%d\n",ans[i]-);
}
}
return ;
}
CDQ分治就是将前半截对后半截的影响拿出来,把偏序问题降维。
三维的经过一次CDQ分治变成两维,四维的可以经过两次CDQ降成两维。
两维偏序问题,一维排序,另一维做树状数组处理就可以。
这里被注释掉的,是一种离散化的姿势,mark一下。