2017.8.17 陌上花开 思考记录

来源:互联网 发布:js 换行符 编辑:程序博客网 时间:2024/05/22 15:21

        CDQ分治其实是很简洁、直白的分治算法、、

        和树分治差不多,都是处理贡献时扫一遍计算贡献,

        它利用了2个单调性和一个选点:

        第一遍按 a  sort,保证x单调

        分出左右区间,  按b  sort   ,保证两边的y单调

        用树状数组,利用z保证只有比z大的有用,只选比z小的点

    

          一共本身二分区间为nlogn,每一层便历n个,快排两个区间n*log(n/2),每个区间调用树状数组logk;

       所以复杂度是O(nlog(n)log(k)+nlog(n)*log(n/2)+nlog(n)),是nlog^2n级的

  

     注意:

      sort的第二个变量是结束位置,应该是下标+1

      树状数组上界不是n而是k

      同样的花合在一起,注意影响及贡献和单独的不一样



码:

#include<iostream>#include<cstdio>#include<algorithm>using namespace std;struct la{int x,y,z,gx,daan;}a[200005];int tong[200005],n,k,tot,s[4000005],i;int lowbit(int o){return o&(-o);}void jia(int wz,int o){for(;wz<=k;wz+=lowbit(wz)){s[wz]+=o;}}int qiu(int wz){int ans=0;for(;wz>0;wz-=lowbit(wz)){ans+=s[wz];}return ans;}bool cmp(la a,la b){if(a.x==b.x)if(a.y==b.y)return a.z<b.z;else return a.y<b.y;else return a.x<b.x;}bool cmp1(la a,la b){return a.x<b.x;}bool cmp2(la a,la b){return a.y<b.y;}void cdq(int l,int r){if(l==r)return;int i;int mid=(l+r)>>1;cdq(l,mid);cdq(mid+1,r);sort(a+l,a+mid+1,cmp2);sort(a+mid+1,a+r+1,cmp2);int z1=l,z2=mid+1;while(z1<=mid&&z2<=r){  if(a[z1].y<=a[z2].y)jia(a[z1].z,a[z1].gx),z1++;else {a[z2].daan+=qiu(a[z2].z);z2++; }}while(z2<=r){a[z2].daan+=qiu(a[z2].z);z2++;    }for(i=l;i<z1;i++)jia(a[i].z,-a[i].gx);sort(a+l,a+r+1,cmp1);}int main(){scanf("%d%d",&n,&k);for(i=1;i<=n;i++){ scanf("%d%d%d",&a[i].x,&a[i].y,&a[i].z);}sort(a+1,a+1+n,cmp);for(i=1;i<=n;i++){if(a[i].x==a[i-1].x&&a[i].y==a[i-1].y&&a[i].z==a[i-1].z)a[tot].gx++,a[tot].daan++;else ++tot,a[tot].x=a[i].x,a[tot].y=a[i].y,a[tot].z=a[i].z,a[tot].gx=1;    }cdq(1,tot);for(i=1;i<=tot;i++)tong[a[i].daan]+=a[i].gx;for(i=0;i<n;i++)printf("%d\n",tong[i]);}


       

原创粉丝点击