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

来源:互联网 发布:积分统计软件 编辑:程序博客网 时间:2024/05/21 19:25

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

听说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 <stdio.h>//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?type<a.type:x<a.x;    }}que[maxn], tmp[maxn];int n;int val[maxn];int lowbit(int x){    return x&-x;}void add(int x, int y){    while(x<maxn)    {        val[x]+=y;        x+=lowbit(x);    }    return; }int sum(int x){    int res=0;    while(x>0)    {        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<mid && q<r)    {       if(que[p]<que[q])       {          if(que[p].type==1)          {             add(que[p].y, que[p].val);          }          tmp[o++]=que[p++];       }        else        {          if(que[q].type==2)          {            ans[que[q].qid]+=que[q].val*sum(que[q].y);    //        printf("%d %d %d %d %d\n", que[q].x, que[q].y, que[q].val, que[q].qid, ans[que[q].qid]);          }          tmp[o++]=que[q++];       }    }    while(q<r)    {          if(que[q].type==2)          {            ans[que[q].qid]+=que[q].val*sum(que[q].y);    //        printf("%d %d %d %d %d\n", que[q].x, que[q].y, que[q].val, que[q].qid, ans[que[q].qid]);          }        tmp[o++]=que[q++];    }    /*    memset(val, 0, sizeof val);    */    for(int i=l; i<p; i++)if(que[i].type==1)add(que[i].y, que[i].val*-1);    while(p<mid)    {        tmp[o++]=que[p++];    }    for(int i=0; i<o; i++)que[i+l]=tmp[i];     return;}int main(){    /*    freopen("mokia.in", "r", stdin);    freopen("mokia.out", "w", stdout);    */        scanf("%*d%d", &n);    int x, y, x1, y1, e, id=1, qid=1;    while(~scanf("%d", &e))    {        if(e==3)break;        if(e==1)        {            scanf("%d%d%d", &que[id].x, &que[id].y, &que[id].val);            que[id].t=id;            que[id].type=1;        }           else         {            scanf("%d%d%d%d", &x, &y, &x1, &y1);            que[id].t=id, que[id].x=x-1, que[id].y=y-1, que[id].val=1, que[id].qid=qid, que[id].type=2;             id++;            que[id].t=id, que[id].x=x-1, que[id].y=y1, que[id].val=-1, que[id].qid=qid, que[id].type=2;             id++;            que[id].t=id, que[id].x=x1, que[id].y=y-1, que[id].val=-1, que[id].qid=qid, que[id].type=2;             id++;            que[id].t=id, que[id].x=x1, que[id].y=y1, que[id].val=1, que[id].qid=qid, que[id].type=2;             qid++;        }        id++;    }    cdq(1, id);    for(int i=1; i<qid; i++)    {        printf("%d\n", ans[i]);    }}


阅读全文
0 0
原创粉丝点击