[BOI2007]Mokia 摩基亚

本文介绍了一种用户定位系统的算法实现,该系统能快速确定用户位置并计算指定区域内的用户数量。通过构建特定的数据结构和运用前缀和算法,解决了大规模数据下的用户定位问题。

Description:

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

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

1502480-20190325221351098-1087271928.png

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

Hint:

\(n \le 2*10^5\)

Solution:

考虑把答案拆成四个矩阵,前缀和运算一下,就是cdq裸题了

#include <map>
#include <set>
#include <stack>
#include <cmath>
#include <queue>
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <iostream>
#include <algorithm>
#define ls p<<1 
#define rs p<<1|1
using namespace std;
typedef long long ll;
const int mxn=2e6+5;
int n,m,cnt,tot,t[mxn],hd[mxn];

inline int read() {
    char c=getchar(); int x=0,f=1;
    while(c>'9'||c<'0') {if(c=='-') f=-1;c=getchar();}
    while(c<='9'&&c>='0') {x=(x<<3)+(x<<1)+(c&15);c=getchar();}
    return x*f;
}
inline void chkmax(int &x,int y) {if(x<y) x=y;}
inline void chkmin(int &x,int y) {if(x>y) x=y;}

struct Q {
    int id,x,y,val,opt;
}q[mxn<<2];

int cmp(Q x,Q y) {
    return x.id<y.id;
}

int cmp1(Q a,Q b) {
    return a.x==b.x?a.y<b.y:a.x<b.x;
}
 
int lb(int x) {return x&-x;}

void mod(int x,int y) {
    while(x<=n) t[x]+=y,x+=lb(x);
}

int query(int x) {
    int res=0;
    while(x) res+=t[x],x-=lb(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);
    sort(q+l,q+mid+1,cmp1); 
    sort(q+mid+1,q+r+1,cmp1);
    int lp=l;
    for(int i=mid+1;i<=r;++i) {
        while(q[lp].x<=q[i].x&&lp<=mid) { //这里没取等调了半年
            if(!q[lp].opt) mod(q[lp].y,q[lp].val);
            ++lp;
        }
        if(q[i].opt) q[i].val+=query(q[i].y);
    }
    for(int i=l;i<lp;++i) 
        if(!q[i].opt) mod(q[i].y,-q[i].val);
}


int main()
{
    int opt,x,y,w,z;
    n=read(); n=read()+1; opt=read();
    while(opt!=3) {
        if(opt==1) 
            ++tot, q[tot].id=tot,q[tot].x=read()+1,q[tot].y=read()+1,q[tot].val=read();
        else {
            x=read(); y=read(); w=read()+1,z=read()+1;
            ++tot, q[tot]=(Q){tot,x,y,0,1};
            ++tot, q[tot]=(Q){tot,w,z,0,1};
            ++tot, q[tot]=(Q){tot,w,y,0,1};
            ++tot, q[tot]=(Q){tot,x,z,0,1};
        }
        opt=read();
    }
    cdq(1,tot); sort(q+1,q+tot+1,cmp);
    for(int i=1;i<=tot;++i) 
        if(q[i].opt) 
            printf("%d\n",q[i].val+q[i+1].val-q[i+2].val-q[i+3].val),i+=3;
    return 0;
}

转载于:https://www.cnblogs.com/list1/p/10597134.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值