洛谷P4390 [BOI2007]Mokia 摩基亚 题解

洛谷P4390 [BOI2007]Mokia 摩基亚 题解

题目链接:P4390 [BOI2007]Mokia 摩基亚

题意:摩尔瓦多的移动电话公司摩基亚(Mokia)设计出了一种新的用户定位系统。和其他的定位系统一样,它能够迅速回答任何形如“用户 C 的位置在哪?”的问题,精确到毫米。但其真正高科技之处在于,它能够回答形如“给定区域内有多少名用户?”的问题。

在定位系统中,世界被认为是一个 w × w w×w w×w 的正方形区域,由 1 × 1 1\times 1 1×1 的方格组成。每个方格都有一个坐标 ( x , y ) (x,y) (x,y) 1 ≤ x , y ≤ w 1\leq x,y\leq w 1x,yw。坐标的编号从 1 1 1 开始。对于一个 4 × 4 4\times 4 4×4 的正方形,就有 1 ≤ x ≤ 4 1\leq x\leq 4 1x4 1 ≤ y ≤ 4 1\leq y\leq 4 1y4(如图):

img

请帮助 Mokia 公司编写一个程序来计算在某个矩形区域内有多少名用户。

这道题的题解区一片互相抄袭的烂货,实在受不了了就来水一篇题解

可以发现这道题目就是个二维数点问题,不知道的推荐看看 这篇博客

然后这道题目,我们不能用归并排序来做

为什么呢?因为这个题目它还有一个维度:时间顺序

因此我们可以使用CDQ分治(第一维是时间,第二维是 x x x ,第三维是 y y y

这里我们甚至不用按时间排序,它本来就是顺序的

注意到 w ≤ 2 × 1 0 6 w\le 2\times 10^6 w2×106有一丢丢大,所以可以不必要地离散化一下 y y y

因此时间复杂度 O ( n log ⁡ 2 n ) O(n\log^2 n) O(nlog2n)

然后就跑到了最优解第一页,嘿嘿树状数组跑的飞快🤤(逃~

代码如下

#include <bits/stdc++.h>
using namespace std;
#define int long long
#define INF 0x3f3f3f3f3f3f3f3f
#define gc() getchar()
#define pc(a) putchar(a)
#define SIZ (int)(1e5+15)
#define lb lower_bound
char buf1[SIZ],*p1,*p2;
char readchar()
{
    if(p1==p2)p1=buf1,p2=buf1+fread(buf1,1,SIZ,stdin);
    return p1==p2?EOF:*p1++;
}
template<typename T>void read(T &k)
{
    char ch=gc();T x=0,f=1;
    while(!isdigit(ch)){if(ch=='-')f=-1;ch=gc();}
    while(isdigit(ch)){x=(x<<1)+(x<<3)+(ch^48);ch=gc();}
    k=x*f;
}
template<typename T>void write(T k)
{
    if(k<0){pc('-');k=-k;}
    static T stk[66];T top=0;
    do{stk[top++]=k%10,k/=10;}while(k);
    while(top){pc(stk[--top]+'0');}
}
#define N (int)(2e6+15)
struct node
{
    int x,y,typ,add,id,ans;
}t[N],b[N];
int w,n,Q,pos,tcnt;
int tree[N],ans[N],tmp[N];
void addQ(int a,int b,int c,int d=0,int e=0)
{
    t[++pos]={a,b,c,d,e};
}
#define lowbit(x) (x&(-x))
void add(int x,int v)
{
    while(x&&x<=n)
    {
        tree[x]+=v;
        x+=lowbit(x);
    }
}
int sum(int x)
{
    int res=0;
    while(x>=1)
    {
        res+=tree[x];
        x-=lowbit(x);
    }
    return res;
}
void init()
{
    for(int i=1; i<=pos; i++)
        tmp[i]=t[i].y;
    sort(tmp+1,tmp+1+pos);
    n=unique(tmp+1,tmp+1+pos)-tmp-1;
    for(int i=1; i<=pos; i++)
        t[i].y=lb(tmp+1,tmp+1+n,t[i].y)-tmp;
}
void cdq(int l,int r)
{
    if(l==r)return;
    int mid=(l+r)>>1;
    cdq(l,mid);cdq(mid+1,r);
    int i=mid+1,j=l,cnt=0;
    for(;i<=r; i++)
    {
        while(t[j].x<=t[i].x&&j<=mid)
        {
            if(t[j].typ==1)add(t[j].y,t[j].add);
            b[++cnt]=t[j++];
        }
        if(t[i].typ==2)t[i].ans+=sum(t[i].y);
        b[++cnt]=t[i];
    }
    for(int i=l; i<j; i++)
        if(t[i].typ==1)add(t[i].y,-t[i].add);
    while(j<=mid)
        b[++cnt]=t[j++];
    for(int i=1; i<=cnt; i++)
        t[l+i-1]=b[i];
}
signed main()
{
    read(w);read(w);
    int op;
    while(read(op),op!=3)
    {
        int a,b,c,d;
        if(op==1)
        {
            read(a);read(b);read(c);
            addQ(a,b,1,c);
        }else if(op==2)
        {
            read(a);read(b);read(c);read(d);++Q;
            addQ(c,d,2,1,Q);
            addQ(a-1,d,2,-1,Q);
            addQ(c,b-1,2,-1,Q);
            addQ(a-1,b-1,2,1,Q);
        }
    }
    init();
    cdq(1,pos);
    for(int i=1; i<=pos; i++)
    {
        if(t[i].typ==2)
            ans[t[i].id]+=t[i].add*t[i].ans;
    }
    for(int i=1; i<=Q; i++)
        write(ans[i]),pc('\n');
    return 0;
}

这里还有非离散化版本的

#include <bits/stdc++.h>
using namespace std;
#define int long long
#define INF 0x3f3f3f3f3f3f3f3f
#define gc() getchar()
#define pc(a) putchar(a)
#define SIZ (int)(1e5+15)
#define lb lower_bound
char buf1[SIZ],*p1,*p2;
char readchar()
{
    if(p1==p2)p1=buf1,p2=buf1+fread(buf1,1,SIZ,stdin);
    return p1==p2?EOF:*p1++;
}
template<typename T>void read(T &k)
{
    char ch=gc();T x=0,f=1;
    while(!isdigit(ch)){if(ch=='-')f=-1;ch=gc();}
    while(isdigit(ch)){x=(x<<1)+(x<<3)+(ch^48);ch=gc();}
    k=x*f;
}
template<typename T>void write(T k)
{
    if(k<0){pc('-');k=-k;}
    static T stk[66];T top=0;
    do{stk[top++]=k%10,k/=10;}while(k);
    while(top){pc(stk[--top]+'0');}
}
#define N (int)(2e6+15)
struct node
{
    int x,y,typ,add,id,ans;
}t[N],b[N];
int w,n,Q,pos,tcnt;
int tree[N],ans[N],tmp[N];
void addQ(int a,int b,int c,int d=0,int e=0)
{
    t[++pos]={a,b,c,d,e};
}
#define lowbit(x) (x&(-x))
void add(int x,int v)
{
    while(x&&x<=w)
    {
        tree[x]+=v;
        x+=lowbit(x);
    }
}
int sum(int x)
{
    int res=0;
    while(x>=1)
    {
        res+=tree[x];
        x-=lowbit(x);
    }
    return res;
}
void cdq(int l,int r)
{
    if(l==r)return;
    int mid=(l+r)>>1;
    cdq(l,mid);cdq(mid+1,r);
    int i=mid+1,j=l,cnt=0;
    for(;i<=r; i++)
    {
        while(t[j].x<=t[i].x&&j<=mid)
        {
            if(t[j].typ==1)add(t[j].y,t[j].add);
            b[++cnt]=t[j++];
        }
        if(t[i].typ==2)t[i].ans+=sum(t[i].y);
        b[++cnt]=t[i];
    }
    for(int i=l; i<j; i++)
        if(t[i].typ==1)add(t[i].y,-t[i].add);
    while(j<=mid)
        b[++cnt]=t[j++];
    for(int i=1; i<=cnt; i++)
        t[l+i-1]=b[i];
}
signed main()
{
    read(w);read(w);
    int op;
    while(read(op),op!=3)
    {
        int a,b,c,d;
        if(op==1)
        {
            read(a);read(b);read(c);
            addQ(a,b,1,c);
        }else if(op==2)
        {
            read(a);read(b);read(c);read(d);++Q;
            addQ(c,d,2,1,Q);
            addQ(a-1,d,2,-1,Q);
            addQ(c,b-1,2,-1,Q);
            addQ(a-1,b-1,2,1,Q);
        }
    }
    cdq(1,pos);
    for(int i=1; i<=pos; i++)
    {
        if(t[i].typ==2)
            ans[t[i].id]+=t[i].add*t[i].ans;
    }
    for(int i=1; i<=Q; i++)
        write(ans[i]),pc('\n');
    return 0;
}

转载请说明出处

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值