hdu 5618 樹套樹和cdq分治

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;
}
發佈了122 篇原創文章 · 獲贊 11 · 訪問量 2萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章