[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-1,y2)-(1,1)(x2,y1-1) $求即可,所以对于每一个询问操作,把他看成四个坐标,求出前缀和就能找到答案

把操作的时间看作一维(时间在前的才可能对后面的操作有影响),把x,y看作后两维,对于\((1,1)(x,y)\),那么问题就转化成了\(timea<timeb xa<xb ya<yb\)的数量,也就是三位偏序模板了

注意几点:

1、树状数组的下标不能为0(0的lowbit的值也是0),所以我们需要把每一个点横纵坐标加一,最后w也要记得+1

2、注意区分询问和加法,在操作树状数组时要区分

给出代码:

#include<bits/stdc++.h>
using namespace std;
#define il inline
#define re register
#define debug printf("Now is Line : %d\n",__LINE__)
il int read()
{
    re int x=0,f=1;re char c=getchar();
    while(c<'0'||c>'9') {if(c=='-') f=-1;c=getchar();}
    while(c>='0'&&c<='9') x=x*10+c-48,c=getchar();
    return x*f;
}
#define lb(x) (x)&-(x)
#define maxn 200005
#define maxm 2000005
struct node
{
    int tim,x,y,val,id;
}e[maxn];
int cnt,a[maxm],w;
il void add(int x,int v)
{
    while(x<=w)
    {
        a[x]+=v;
        x+=lb(x);
    }
}
il int query(int x)
{
    int ans=0;
    while(x)
    {
        ans+=a[x];
        x-=lb(x);
    }
    return ans;
}
il bool cmp1(node a,node b)
{
    return (a.x==b.x)?(a.y<b.y):(a.x<b.x);
}
il bool cmp(node a,node b)
{
    return a.tim<b.tim;
}
il 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+mid+1,cmp1);
    sort(e+mid+1,e+r+1,cmp1);
    re int i=l,j=mid+1;
    for(;j<=r;++j)
    {
        while(e[i].x<=e[j].x&&i<=mid)
        {
            if(e[i].id==0) add(e[i].y,e[i].val);
            ++i;
        }
        if(e[j].id==1) e[j].val+=query(e[j].y);
    }
    for(j=l;j<i;++j) if(e[j].id==0) add(e[j].y,-e[j].val);
}
int main()
{
    read(),w=read()+1;
    int opt=read();
    while(opt!=3)
    {
        if(opt==1)
        {
            int x=read()+1,y=read()+1,val=read();
            e[++cnt]=(node){cnt,x,y,val,0};
        }
        else
        {
            int x1=read(),y1=read(),x2=read()+1,y2=read()+1;
            e[++cnt]=(node){cnt,x1,y1,0,1};
            e[++cnt]=(node){cnt,x2,y2,0,1};
            e[++cnt]=(node){cnt,x2,y1,0,1};
            e[++cnt]=(node){cnt,x1,y2,0,1};
        }
        opt=read();
    }
    CDQ(1,cnt);
    sort(e+1,e+cnt+1,cmp);
    for(re 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;
}

原文地址:https://www.cnblogs.com/bcoier/p/10293084.html

时间: 2024-08-09 05:38:19

[BOI2007]Mokia 摩基亚的相关文章

【BOI2007】摩基亚Mokia

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

摩基亚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的方格组成.每

【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

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

[BOI2007] Mokia

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

[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<

题解报告——Mokia

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