[BOI2007] Mokia

题目描述

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

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

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

输入输出格式

输入格式:

有三种命令,意义如下:

命令 参数 意义

  • 0 W 初始化一个全零矩阵。本命令仅开始时出现一次。
  • 1 x y A 向方格(x,y)中添加A个用户。A是正整数。
  • 2 X1 Y1 X2 Y2 查询X1<=x<=X2,Y1<=y<=Y2所规定的矩形中的用户数量
  • 3 无参数 结束程序。本命令仅结束时出现一次。

输出格式:

对所有命令2,输出一个一行整数,即当前询问矩形内的用户数量。

输入输出样例

输入样例#1:

0 4
1 2 3 3
2 1 1 3 3
1 2 2 2
2 2 2 3 4
3

输出样例#1:

3
5

说明

1<=W<=2000000

1<=X1<=X2<=W

1<=Y1<=Y2<=W

1<=x,y<=W

0<A<=10000

命令1不超过160000个。

命令2不超过10000个。

CDQ求解三维偏序模板题。

#include<bits/stdc++.h>
#define ll long long
using namespace std;
const int maxn=200005;
struct node{
    int x,y,z,num,FL;
}a[maxn];
int opt,A,B,C,D,cnt=0,W,qnum;
int ans[maxn],f[maxn],T;

inline bool cmp3(node x,node y){
    return x.z==y.z?x.num<y.num:x.z<y.z;
}

inline bool cmp2(node x,node y){
    return x.y==y.y?cmp3(x,y):x.y<y.y;
}

inline bool cmp1(node x,node y){
    return x.x==y.x?cmp2(x,y):x.x<y.x;
}

inline void update(int x,int y){
    for(;x<=T;x+=x&-x) f[x]+=y;
}

inline int query(int x){
    int an=0;
    for(;x;x-=x&-x) an+=f[x];
    return an;
}

void cdq(int L,int R){
    if(L>=R) return;
    int mid=L+R>>1,i,j;
    cdq(L,mid),cdq(mid+1,R);
    sort(a+L,a+mid+1,cmp2);
    sort(a+mid+1,a+R+1,cmp2);

    for(i=L,j=mid+1;j<=R;j++){
        for(;i<=mid&&a[i].y<=a[j].y;i++) if(!a[i].num) update(a[i].z,a[i].FL);
        if(a[j].num) ans[a[j].num]+=a[j].FL*query(a[j].z);
    }

    for(i--;i>=L;i--) if(!a[i].num) update(a[i].z,-a[i].FL);
}

int main(){
    scanf("%d%d",&opt,&W);
    while(scanf("%d",&opt)==1&&opt!=3){
        T++;
        if(opt==1){
            scanf("%d%d%d",&A,&B,&C);
            a[++cnt]=(node){A,B,T,0,C};
        }
        else{
            qnum++;
            scanf("%d%d%d%d",&A,&B,&C,&D);
            a[++cnt]=(node){C,D,T,qnum,1};
            a[++cnt]=(node){A-1,B-1,T,qnum,1};
            a[++cnt]=(node){A-1,D,T,qnum,-1};
            a[++cnt]=(node){C,B-1,T,qnum,-1};
        }
    }

    sort(a+1,a+cnt+1,cmp1);
    cdq(1,cnt);

    for(int i=1;i<=qnum;i++) printf("%d\n",ans[i]);
    return 0;
}

  

原文地址:https://www.cnblogs.com/JYYHH/p/8809860.html

时间: 2024-10-12 15:52:10

[BOI2007] Mokia的相关文章

[BZOJ 1176&amp;COGS 1752][BOI2007]Mokia(CDQ分治)

Description 维护一个W*W的矩阵,初始值均为S.每次操作可以增加某格子的权值,或询问某子矩阵的总权值.修改操作数M<=160000,询问数Q<=10000,W<=2000000. Solution 这道在BZOJ上是权限题啊…然而我在cogs上找到了它 依旧是CDQ分治的论文题,CDQ太强辣… 把查询拆成四个前缀和的形式,在CDQ分治中用时间把操作分为两部分,保证两部分的x各自单调(只有x较小的操作才能对较大的操作产生影响),然后用树状数组维护y这一维 #include<

[BOI2007]Mokia 摩基亚

upd:\((x1,y1)(x2,y2)\)表示以\((x1,y1)\)为左上端点 \((x2,y2)\)为右下端点的矩形 本来以为是一道二位树状数组的模板,但是看数据范围之后就放弃了,边界既然到了2000000,那么我们只能使用其他办法来代替树状数组 于是,CDQ分治就诞生了! 此题我们可以把问题转化成cdq分治模板 回忆一下二位树状数组是怎么求二维区间查询的:对于区间[x1,y1][x2,y2],我们把它转化成$ (1,1)(x1-1,y1-1)+(1,1)(x2,y2)-(1,1)(x1-

【BOI2007】摩基亚Mokia

P1948 - [BOI2007]摩基亚Mokia Description 摩尔瓦多的移动电话公司摩基亚(Mokia)设计出了一种新的用户定位系统.和其他的定位系统一样,它能够迅速回答任何形如"用户C的位置在哪?"的问题,精确到毫米.但其真正高科技之处在于,它能够回答形如"给定区域内有多少名用户?"的问题. 在定位系统中,世界被认为是一个W * W的正方形区域,由1 * 1的方格组成.每个方格都有一个坐标(x,y),1<=x,y<=W.坐标的编号从1开始

COJS 1752. [BOI2007]摩基亚Mokia

1752. [BOI2007]摩基亚Mokia ★★★   输入文件:mokia.in   输出文件:mokia.out   简单对比时间限制:5 s   内存限制:128 MB [题目描述] 摩尔瓦多的移动电话公司摩基亚(Mokia)设计出了一种新的用户定位系统.和其他的定位系统一样,它能够迅速回答任何形如“用户C的位置在哪?”的问题,精确到毫米.但其真正高科技之处在于,它能够回答形如“给定区域内有多少名用户?”的问题. 在定位系统中,世界被认为是一个W*W的正方形区域,由1*1的方格组成.每

「BOI2007」Mokia

「BOI2007」Mokia 传送门 把查询拆成四部分然后容斥计算答案(二维前缀和) 然后 \(\text{CDQ}\) 分治算答案. 参考代码: #include <algorithm> #include <cstdio> #define rg register #define file(x) freopen(x".in", "r", stdin), freopen(x".out", "w", std

【COGS1752】 BOI2007—摩基亚Mokia

http://cogs.pro/cogs/problem/problem.php?pid=1752 (题目链接) 题意 给出$n*n$的棋盘,单点修改,矩阵查询. Solution 离线以后CDQ分治.每一层按照$Y$排序,然后询问用前缀和拆成$4$个,树状数组维护一下就可以了. 细节 ? 代码 // cogs1752 #include<algorithm> #include<iostream> #include<cstdlib> #include<cstring

【BOI2007】【BZOJ1176】Mokia

1176: [Balkan2007]Mokia Time Limit: 30 Sec Memory Limit: 162 MB Submit: 1059 Solved: 432 [Submit][Status][Discuss] Description 维护一个W*W的矩阵,初始值均为S.每次操作可以增加某格子的权值,或询问某子矩阵的总权值.修改操作数M<=160000,询问数Q<=10000,W<=2000000. Input 第一行两个整数,S,W;其中S为矩阵初始值;W为矩阵大小

COGS1752. [BOI2007]摩基亚Mokia CDQ

CDQ的板子题 #include<cstdio> #include<cstring> #include<iostream> #include<algorithm> #define MAXN 2000010 using namespace std; inline int read() { int sum=0; char ch=getchar(); while(ch<'0'||ch>'9')ch=getchar(); while(ch>='0'

Bzoj1176:Mokia&amp;Cogs1752:[BOI2007]摩基亚Mokia

题目 Cogs 没有Bzoj的权限号 Sol 离线,\(CDQ\)分治,把询问拆成\(4\)个,变成每次求二位前缀和 那么只要一个修改操作(关键字为时间,\(x\),\(y\))都在这个询问前,就可以累计答案 那么就成了偏序问题了,直接\(CDQ\) 注意当\(x\)相等时要把修改丢在前面 # include <bits/stdc++.h> # define IL inline # define RG register # define Fill(a, b) memset(a, b, size