cogs 1752 [BOI2007]摩基亚Mokia(cdq分治+树状数组)

数据范围过大,所以没有办法二维树状数组和二维线段树什么的。

听说kdtree可做?然而还不会。

这时候cdq分治就派上用场了,首先它不需要二维的空间,所有空间上是没问题的,然后时间复杂度也可以,具体时间复杂度分析下面再说。

这个问题其实可以看成一个三维偏序问题,(时间,横坐标,纵坐标)。

三维貌似看起来有些头疼,假如是二维呢,比如 问题是动态加点,询问一条线段里包含的权值和,

那样就是(时间,坐标)的一个二维偏序,对于我一个查询可以看成(a,b),(a,c)的两个偏序,a代表查询的时间,b,c代表线段的两个端点,那么我们如果找到时间小于a,坐标小于c的的权值和,再减去同样的比较方法小于(a,b)的权值和,不就求出了这一时刻这条线段里包含的权值和了嘛。

那么三维不就是把坐标扩大,按照求二维前缀和的方式去求容斥一下就好了?

我们需要先将一次询问转换为四次不同的二维前缀和查询操作,然后对于每一个询问,我们需要求出左区间(时间小于自己)里,横坐标小于自己纵坐标也小于自己的权值和,

时间已经满足,横坐标的话可以通过cdq分治时顺带的归并排序确定出横坐标小于自己的连续操作区间,但是纵坐标就需要用树状数组统计一下相应的权值了,在查询的时候再求出纵坐标小于自己的点的权值,每次分治的结束的时候都清空下树状数组,就做完了。

cdq分治递归logn层,每层o(n)的操作,然后加上一个树状数组的logn,时间复杂度就是nlog^nlog^2了。

cogs oj给出数据什么的真的好评,但是我数组开小了,应该re竟然返回wa了。

代码:

#include 

//using namespace std;
const int maxn=2e6+5;
int ans[10005];
struct node
{
    int t;
    int x;
    int y;
    int qid;
    int val;
    int type;
    bool operator <(const node &  a)const 
    {
        return a.x==x?type0)
    {
        res+=val[x];

        x-=lowbit(x);
    }
    return res;
}


void cdq(int l, int r)
{
    if(r-l<=1)return;
    int mid=(l+r)>>1;
    cdq(l, mid);
    cdq(mid, r);
    int p=l, q=mid, o=0;
//    printf("%d %d\n", l, r);
    while(p


你可能感兴趣的:(acm,codeproblem)