[BOI2007]Mokia 摩基亚
Posted bcoier
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了[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
",__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
",e[i].val+e[i+1].val-e[i+2].val-e[i+3].val);
i+=3;
}
}
return 0;
}
以上是关于[BOI2007]Mokia 摩基亚的主要内容,如果未能解决你的问题,请参考以下文章
P4390 [BOI2007]Mokia 摩基亚(cdq分治)
COGS1752. [BOI2007]摩基亚Mokia CDQ