码迷,mamicode.com
首页 > 其他好文 > 详细

cdq分治

时间:2019-03-17 13:39:23      阅读:153      评论:0      收藏:0      [点我收藏+]

标签:处理   max   for   +=   题意   efi   mes   三维   \n   

A.三维偏序问题

题意

给你 \(n\) 个三元组 \((x_i,y_i,z_i)\) ,求对于每一个 \((x_i,y_i,z_i)\)\(x_j<x_i,y_j<y_i,z_j<z_i\) 的个数。 \((n\le 100000)\)

对于一维偏序,直接排序。
对于二维偏序,先排序排掉一维 \(x\) ,再对另一维 \(y\) 用树状数组或归并排序维护。(做法同“求逆序对”)
对于三维偏序,先排序排掉一维 \(x\) ,然后考虑分治,先处理区间 \([l,mid],[mid+1,r]\) ,保持 \(y\) 有序,然后归并 \(x\) ,同时用树状数组维护第三维 \(z\)
对于更高维的偏序,理论上是可行的,每次复杂度加一个 \(\log\)

Template Code

#include<cstdio>
#include<algorithm>
#define maxn 100003
#define maxv 100000
using namespace std;
template<typename tp>
void read(tp& x){
    x=0;
    char c=getchar();
    bool sgn=0;
    while((c<'0'||c>'9')&&c!='-')c=getchar();
    if(c=='-')sgn=1,c=getchar();
    while(c>='0'&&c<='9')x=(x<<3)+(x<<1)+c-'0',c=getchar();
    if(sgn)x=-x;
}
template<typename tp>
void write(tp x){
    if(x<0)putchar('-'),write(-x);
    else{
        if(x>=10)write(x/10);
        putchar(x%10+'0');
    }
}
struct T{
    int a,b,c,num;
    bool operator ==(const T& x){return a==x.a&&b==x.b&&c==x.c;}
}a[maxn];
int n,rig[maxn],t[maxn],ANS[maxn];
bool cmp(const T& x,const T& y){return x.a!=y.a?x.a<y.a:(x.b!=y.b?x.b<y.b:x.c<y.c);}
bool cmp1(const T& x,const T& y){return x.b!=y.b?x.b<y.b:(x.c!=y.c?x.c<y.c:x.a<y.a);}
void add(int pos,int k){
    while(pos<=maxv)t[pos]+=k,pos+=pos&-pos;
}
int query(int pos){
    int ret=0;
    while(pos)ret+=t[pos],pos-=pos&-pos;
    return ret;
}
void cdq(int l,int r){
    if(l==r)return;
    int mid=(l+r)>>1;
    cdq(l,mid),cdq(mid+1,r);
    sort(a+l,a+r+1,cmp1);
    for(int i=l;i<=r;i++){
        if(a[i].a<=mid)add(a[i].c,1);
        else ANS[a[i].num]+=query(a[i].c);
    }
    for(int i=l;i<=r;i++){
        if(a[i].a<=mid)add(a[i].c,-1);
    }
}
int main(){
    int T;
    read(T);
    while(T--){
        read(n);
        for(int i=1;i<=n;i++)ANS[i]=0;
        for(int i=1;i<=n;i++){
            read(a[i].a),read(a[i].b),read(a[i].c);
            a[i].num=i;
        }
        sort(a+1,a+n+1,cmp);
        for(int i=1,j=1;i<=n;){
            while(j<=n&&a[j]==a[i]){
                j++;
            }
            while(i<j){
                rig[a[i].num]=a[j-1].num;
                i++;
            }
        }
        for(int i=1;i<=n;i++)a[i].a=i;
        cdq(1,n);
        for(int i=1;i<=n;i++)write(ANS[rig[i]]),putchar('\n');
    }
    return 0;
}

B.

题意

\(n\) 个在三维空间中的球,一个球 \(i\) 能击中另一个 \(j\) 的条件是 \(x_i<x_j,y_i<y_j,z_i<z_j\) 。现在你能够打出某一个球,问最多有几个球能被击中,并输出击中最多个数的球的方案数。\((n\le 100000)\)

cdq分治

标签:处理   max   for   +=   题意   efi   mes   三维   \n   

原文地址:https://www.cnblogs.com/BlogOfchc1234567890/p/10546348.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!