Jam’s problem again
Time Limit: 5000/2500 MS (Java/Others) Memory Limit: 65536/65536 K (Java/Others)
Total Submission(s): 1746 Accepted Submission(s): 623
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.
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)
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
题意:3维排序
做法:
1,树套树:
建n棵树,把(x,y,z)按照x的大小插入,查到第y颗树的z节点,这样如果想查询比(x,y,z)小的节点,只需要在1-y颗树上计算1-z节点的和,这样每次操作的复杂度是nlogn,可以用树状数组来优化。
我们可以用树状数组处理一维数组上的区间求和,那么可以拓展到二维空间的区间求和,现在有y棵树,每颗树有z个节点,但是第y棵代表的是一段区间上的树上的节点和,这个区间就是树状数组上每个数代表的区间。可以用数组模拟树,就不用n×n×logn的空间复杂度了。
但是有一个疑问就是,我认为树状数组每次插入一个结点的时候最多要修改log棵树,每颗树上最多增加log个节点,那么每次操作在树上最多增加log*log个节点,为什么空间不用开n×logn×logn?
待解决—
#include<bits/stdc++.h>
using namespace std;
const int N = 1e5+7;
struct node{
int x,y,z,id;
bool operator<(const node &p)const{
if(x != p.x) return x< p.x;
if(y != p.y) return y < p.y;
return z < p.z;
}
bool operator==(const node &p)const{
return p.x == x && p.y == y && p.z == z;
}
};
node pt[N];
int ans[N];
struct Tree{
int f[N],ls[N*50],rs[N*50],su[N*50];
int mx1,mx2,top = 0;;
void init(int x,int y){
memset(f,0,sizeof(f));
top = 1;
mx1 = x,mx2 = y;
}
int newnode(){
ls[top] = 0;
rs[top] = 0;
su[top] = 0;
return top++;
}
void update(int &rt,int x,int l,int r){
if(rt == 0) rt = newnode();
if(l == r){
su[rt] ++;
return ;
}
int mid = l+r>>1;
if(x <= mid) update(ls[rt],x,l,mid);
else update(rs[rt],x,mid+1,r);
su[rt] = su[ls[rt]]+su[rs[rt]];
}
void add(int y,int z){
//cout << y << ' '<<z <<"###" << endl;
while(y <= mx1){
update(f[y],z,1,mx2);
y += lowbit(y);
}
}
int get(int x,int y){
int sum = 0;
while(x){
sum += query(f[x],1,y,1,mx2);
x -= lowbit(x);
}
return sum;
}
int query(int rt,int L,int R,int l,int r){
if(rt == 0) return 0;
if(L <= l && R >= r){
return su[rt];
}
int mid = l+r>>1;
int ret = 0;
if(mid >= L){
ret += query(ls[rt],L,R,l,mid);
}
if(mid < R) {
ret += query(rs[rt],L,R,mid+1,r);
}
return ret;
}
int lowbit(int x){
return x&(-x);
}
}tree;
int main(){
int T;
cin >> T;
while(T--){
int n;
scanf("%d",&n);
for(int i= 1;i <= n;i ++){
scanf("%d %d %d",&pt[i].x,&pt[i].y,&pt[i].z);
pt[i].id = i;
}
int my=0,mz = 0;
for(int i = 1;i <= n;i ++) my = max(my,pt[i].y),mz = max(mz,pt[i].z);
tree.init(my,mz);
sort(pt+1,pt+1+n);
vector<node> vp;
vp.push_back(pt[1]);
for(int i = 2;i <= n; i++){
if(!(pt[i] == pt[i-1])){
for(int j = 0;j < vp.size();j ++){
tree.add(vp[j].y,vp[j].z);
}
int ret = tree.get(vp[0].y,vp[0].z);
for(int j= 0;j < vp.size();j ++){
ans[vp[j].id] =ret;
}
vp.clear();
vp.push_back(pt[i]);
}
else vp.push_back(pt[i]);
}
for(int j = 0;j < vp.size();j ++){
tree.add(vp[j].y,vp[j].z);
}
int ret = tree.get(vp[0].y,vp[0].z);
for(int j = 0;j < vp.size();j ++){
ans[vp[j].id] = ret;
}
for(int i= 1;i <= n;i ++){
printf("%d\n",ans[i]-1);
}
}
return 0;
}
cdq分治:
cdq分治的思想,对于一个区间,计算左区间对右区间造成的影响,然后递归处理。
感觉一个大佬说的挺好,分治的含义,分就是把问题分解成小问题,治:就是通过小问题的答案,得到大问题的答案。
#include<bits/stdc++.h>
using namespace std;
const int N = 1e5+7;
struct node{
int x,y,z,id;
bool operator<(const node &p)const{
if(x != p.x) return x < p.x;
if(y != p.y) return y < p.y;
if(z != p.z) return z < p.z;
}
bool operator==(const node &p)const{
return x==p.x&&y==p.y&&z==p.z;
}
};
node pt[N];
int ans[N];
bool cmpy(node a,node b){
return a.y < b.y;
}
struct Bit{
int sum[N],mx;
void init(int x){
mx = x;
memset(sum,0,sizeof(sum));
}
void add(int x,int d){
while(x <= mx){
sum[x] += d;
x += lowbit(x);
}
}
int query(int x){
int su = 0;
while(x){
su += sum[x];
x -= lowbit(x);
}
return su;
}
int lowbit(int x){
return x&(-x);
}
}bit;
void cdq(int l,int r){
//cout << l << ' '<<r << endl;
if(l == r) return ;
int mid = l+r>>1;
cdq(l,mid);
cdq(mid+1,r);
sort(pt+l,pt+mid+1,cmpy);
sort(pt+mid+1,pt+r+1,cmpy);
int j =l;
for(int i = mid+1;i <= r;i ++){
while(j <= mid && pt[j].y <= pt[i].y ){
bit.add(pt[j].z,1);
j++;
}
ans[pt[i].id] += bit.query(pt[i].z);
}
for(int i = l;i < j;i ++) bit.add(pt[i].z,-1);
}
int main(){
int T;
cin >> T;
for(int kase = 1;kase <= T;kase ++){
int n;
scanf("%d",&n);
memset(ans,0,sizeof(ans));
bit.init(1e5);
for(int i = 1;i <= n;i ++){
scanf("%d %d %d",&pt[i].x,&pt[i].y,&pt[i].z);
pt[i].id = i;
}
sort(pt+1,pt+1+n);
cdq(1,n);
sort(pt+1,pt+1+n);
vector<int> vp;
vp.push_back(pt[1].id);
for(int i =2;i <= n;i ++){
if(!(pt[i] == pt[i-1])){
for(int j =0;j < vp.size();j ++) ans[vp[j]] = ans[pt[i-1].id];
vp.clear();
vp.push_back(pt[i].id);
}
else vp.push_back(pt[i].id);
}
for(int j = 0;j < vp.size();j ++) ans[vp[j]] = ans[pt[n].id];
for(int i = 1;i <= n;i ++){
printf("%d\n",ans[i]);
}
}
return 0;
}