Mokia(三维偏序)P4390

提到cdq,就不得不提这道该死的,挨千刀的题目了。

极简题面:

给定一个二维平面,在ti时刻会在(xi,yi)放一个点,会在tj时刻查询一个方框里面的点的数量

看道题就是二维线段树乱搞啊,这么水???

数据范围劝退警告

单是一维都快有点吃不消了...1e6*1e6的数组?几个GB???

。。。

于是,伟大的CDQ分治出场了。

题面其实可以这样翻译:

按时插入点,询问小于(x,y)且时间也小于当前点的点的个数

这不就是CDQ的事吗?比模板题还要裸。。。

但是可能要差分一下(二维差分)因为统计的是点与00组成的大矩形,所以要剪去两个矩形,再加上一个小矩形,所以要统计四个点的偏序

总结一下,就是cdq。

第一维时间,第二维x,第三维y

一定要离线做

于是开始了愉快的CDQ

#include<bits/stdc++.h>
using namespace std;
const int maxn=505;

struct node
{
    int time,x,y,val,id;
}e[maxn];
int m,cnt,t[maxn<<1],a[maxn],ans[maxn];
inline int lowbit(int x)
{
    return x & - x ;
}
void add(int x,int y)
{
    for(;x<=m;x+=lowbit(x))
    {
        t[x]+=y;
    }
}
int ask(int x)
{
    int res=0;
    for(;x;x-=lowbit(x))
    {
        res+=t[x];
    }
    return res;
}
bool cmp2(node a,node b)
{
    if(a.x!=b.x)return a.x<b.x;
    if(a.y!=b.y)return a.y<b.y;
    //else        return a.time<b.time;
}
bool cmp(node a,node b)
{
    return a.time<b.time;
}
void cdq(int l,int r)
{
    if(l==r)return;
    int mid=l+r>>1;
    cdq(l,mid);
    cdq(mid+1,r);
    sort(e+l,e+1+r,cmp2);
    for(int i=l;i<=r;i++)
    {
        if(e[i].x<=mid&&e[i].id==0)
        add(e[i].y,e[i].val);
        else e[i].val+=ask(e[i].y);
    }
    for(int i=l;i<=r;i++)
    {
        if(e[i].x<=mid&&e[i].id==0)
        add(e[i].y,-e[i].val);
    }
}
int read()
{
    int f=1,x=0;char s=getchar();
    while(s>'9'||s<'0'){if(s=='-')f=-1;s=getchar();}
    while(s<='9'&&s>='0'){x=x*10+s-'0';s=getchar();}
    return x*f;
}
int main()
{
    read();
    m=read();
    int flag=read();
    while(flag!=3)
    {
        if(flag==1)
        {
            int x=read()+1,y=read()+1,val=read();
            e[++cnt]=(node){cnt,x,y,val,0};
        }
        else
        {
            int x1=read(),yl=read(),x2=read()+1,y2=read()+1;
            e[++cnt]=(node){cnt,x1,yl,0,1};//数据结构体化
            e[++cnt]=(node){cnt,x2,y2,0,1};
            e[++cnt]=(node){cnt,x2,yl,0,1};
            e[++cnt]=(node){cnt,x1,y2,0,1};
        }
        flag=read();
    }
    cdq(1,cnt);然后硬cdq就行了
    sort(e+1,e+cnt+1,cmp);
    for(int i=1;i<=cnt;++i)
    {
        if(e[i].id==1)
        {
            printf("%d\n",e[i].val+e[i+1].val-e[i+2].val-e[i+3].val);
            i+=3;
        }
    }
    return 0;
}

(完)

posted @ 2019-08-04 22:08  阿基米德的澡盆  阅读(208)  评论(0编辑  收藏  举报