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;
}