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

猜你喜欢

转载自blog.csdn.net/zstu_zy/article/details/81126973
今日推荐