zoukankan      html  css  js  c++  java
  • CDQ分治学习笔记

    CDQ分治是一种神奇的分治算法

    它的核心思想大致是这样的

    将所有的操作看成一个区间

    一个[L,R]的区间分为[L,mid][mid+1,R]这两个子问题

    然后处理[L,mid]这个区间对[mid+1,R]这个区间的贡献

    这样讲解十分抽象,我们还是来看几个实际问题

    二维偏序问题:

      给定N个有序对(a,b),求对于每个(a,b),满足a2<a且b2<b的有序对(a2,b2)有多少个

     我们现将所有点排序按一维,这样右区间就不会对左区间产生影响,就可以CDQ了

    在具体处理左边区间对右边影响时,

    我们将[L,mid]和[mid+1,R]再分别按另一维排序

    然后用两个指针扫一下,就好了

    我们设想一下将二维的偏序加到三维:

      其实做法是差不多的

    一维排序,一维CDQ一维树状数组

    具体处理时我们将[L,min],[mid+1,R]排序后用两个指针扫时

    遇到左边小于右边的情况就将树状数组在a[i].z处加上1

    然后在j处的答案就是sum(a[j].z)

    上代码(洛谷3810)

    # include<iostream>
    # include<cstdio>
    # include<algorithm>
    # include<cmath>
    # include<cstring>
    using std::sort;
    inline int read()
    {
        int x=0;
        char ch=getchar();
        while(ch>'9' || ch<'0')
        ch=getchar();
        while(ch>='0' && ch<='9') x=x*10+ch-'0',ch=getchar();
        return x;
    }
    const int mn = 100005;
    struct element{
    int x,y,z,s,ans;
    };
    element a[mn],b[mn];
    int tot,ans[mn];
    bool cmp1(element m,element n)//按x排序 
    {
        if(m.x==n.x && m.y==n.y) return m.z<n.z;
        else if(m.x==n.x) return m.y<n.y;
        else return m.x<n.x;
    }
    bool cmp2(element m,element n)//按y排序 
    {
        if(m.y==n.y) return m.z<n.z;
        return m.y<n.y; 
    }
    int n,k;
    struct BIT{
    int siz,tr[mn*2];
    void add(int i,int x)
    {
        for(i;i<=siz;i+=(i&-i))
           tr[i]+=x;
    }
    int sum(int i)
    {
        int ret=0;
        for(i;i;i-=(i&-i))
          ret+=tr[i];
        return ret;
    }
    }T;
    void CDQ(int l,int r)
    {
        if(l==r) return ;
        int mid=l+r>>1;
        CDQ(l,mid);
        CDQ(mid+1,r);
        sort(b+l,b+mid+1,cmp2);
        sort(b+mid+1,b+r+1,cmp2);
        int i=l,j=mid+1;
        while(j<=r)
        {
            while(i<=mid && b[i].y<=b[j].y)
            {
                T.add(b[i].z,b[i].s);
                i++;
            }
            b[j].ans+=T.sum(b[j].z);
            j++;
        }
        for(int s=l;s<i;s++)
         T.add(b[s].z,-b[s].s);
    }
    int main()
    {
        n=read(),k=read();
        T.siz=k;
        for(int i=1;i<=n;i++)
            a[i].x=read(),a[i].y=read(),a[i].z=read();
        sort(a+1,a+1+n,cmp1);
        int cnt=0;
        for(int i=1;i<=n;i++)
        {
            cnt++;
            if(a[i].x!=a[i+1].x || a[i].y!=a[i+1].y || a[i].z!=a[i+1].z)
            {
                b[++tot]=a[i];
                b[tot].s=cnt;
                cnt=0;
            }
        }
        CDQ(1,tot);
        /*for(int i=1;i<=tot;i++)
         printf("%d ",b[i].ans);
         printf("
    ");*/
        for(int i=1;i<=tot;i++)
            ans[b[i].ans+b[i].s-1]+=b[i].s;
        for(int i=0;i<n;i++)
           printf("%d
    ",ans[i]);
        return 0;
    }

    (未完待更)

  • 相关阅读:
    135 01 Android 零基础入门 02 Java面向对象 07 Java多态 03 多态的实现(难点) 02 向上转型
    leetcode-----169. 多数元素
    leetcode-----167. 两数之和 II
    leetcode-----136. 只出现一次的数字
    leetcode-----125. 验证回文串
    leetcode-----122. 买卖股票的最佳时机 II
    java实体类和json串字段名称不一致或者与map中字段名称不一致使用注解转化
    如何优雅的将Object转换成List
    java中远程调用接口springboot
    返回前端页面的属性名称和实体类的名称不一致用@JsonProperty
  • 原文地址:https://www.cnblogs.com/logeadd/p/9305687.html
Copyright © 2011-2022 走看看