洛谷 P4390 [BOI2007]Mokia 摩基亞 解題報告
P4390 [BOI2007]Mokia 摩基亞
題目描述
摩爾瓦多的行動電話公司摩基亞(\(Mokia\))設計出了一種新的使用者定位系統。和其他的定位系統一樣,它能夠迅速回答任何形如“使用者\(C\)的位置在哪?”的問題,精確到毫米。但其真正高科技之處在於,它能夠回答形如“給定區域內有多少名使用者?”的問題。
在定位系統中,世界被認為是一個\(W\times W\)的正方形區域,由\(1\times1\)的方格組成。每個方格都有一個座標\((x,y)\),\(1\le x,y\le W\)。座標的編號從\(1\)開始。對於一個\(4\times4\)的正方形,就有\(1\le x\le 4,1\le y\le 4\)
請幫助\(Mokia\)公司編寫一個程式來計算在某個矩形區域內有多少名使用者。
輸入輸出格式
輸入格式:
有三種命令,意義如下:
命令 引數 意義
0 W
初始化一個全零矩陣。本命令僅開始時出現一次。1 x y A
向方格\((x,y)\)中新增\(A\)個使用者。\(A\)是正整數。2 X1 Y1 X2 Y2
查詢\(X_1\le x\le X_2,Y_1\le y\le Y_2\)所規定的矩形中的使用者數量3
無引數 結束程式。本命令僅結束時出現一次。
輸出格式:
對所有命令\(2\),輸出一個一行整數,即當前詢問矩形內的使用者數量。
說明
對於所有資料:
\(1\le W\le 2000000\)
\(1\le X_1\le X_2\le W\)
\(1\le Y_1\le Y_2\le W\)
\(1\le x,y\le W\)
\(0<A\le 10000\)
命令\(1\)不超過\(160000\)個。
命令\(2\)不超過\(10000\)個。
之前做了個園丁的題目,是所有詢問在修改之後的。
於是直接把四維偏序的一維搞成區間操作\(O(n\log^2n)\)水過去了。
然後這個題就萎掉了,想了一會兒還是三個\(\log\),於是打算拿樹套樹水過去。
結果套的線段樹\(MLE\)了,無語...
然後看了看正解,發現直接對矩形容斥就可以了。
就是把一個矩形\((a,b),(c,d)\)拆成\((1,1),(a-1,b-1)\)、\((1,1),(a-1,d)\)、\((1,1),(c,b-1)\)、\((1,1),(c,d)\)四個做。
然後就又成了三維偏序...
Code:
#include <cstdio>
#include <algorithm>
const int N=2e5+10;
int n,m,k,op,ans[N],s[N<<2],dx[N<<2],cntx,dy[N<<2],cnty;
void add(int x,int d){while(x<=cnty)s[x]+=d,x+=x&-x;}
int ask(int x){int sum=0;while(x)sum+=s[x],x-=x&-x;return sum;}
struct node
{
int a,b,c,op;
bool friend operator <(node n1,node n2)
{
return n1.a==n2.a?n1.op<n2.op:n1.a<n2.a;
}
}q[N],qs[N];
void CDQ(int l,int r)
{
if(l==r) return;
int mid=l+r>>1;
CDQ(l,mid),CDQ(mid+1,r);
int lp=l,rp=mid+1,loc=l-1;
while(lp<=mid&&rp<=r)
{
if(q[lp]<q[rp])
{
if(!q[lp].op) add(q[lp].b,q[lp].c);
qs[++loc]=q[lp++];
}
else
{
if(q[rp].op) ans[q[rp].op]+=q[rp].c*ask(q[rp].b);
qs[++loc]=q[rp++];
}
}
while(rp<=r)
{
if(q[rp].op) ans[q[rp].op]+=q[rp].c*ask(q[rp].b);
qs[++loc]=q[rp++];
}
for(int i=l;i<lp;i++) if(!q[i].op) add(q[i].b,-q[i].c);
while(lp<=mid) qs[++loc]=q[lp++];
for(int i=l;i<=r;i++) q[i]=qs[i];
}
int main()
{
scanf("%d%d",&n,&n);
scanf("%d",&op);int a,b,c,d;
while(op!=3)
{
if(op==1)
{
++m;
scanf("%d%d%d",&q[m].a,&q[m].b,&q[m].c);
dx[++cntx]=q[m].a,dy[++cnty]=q[m].b;
}
else
{
scanf("%d%d%d%d",&a,&b,&c,&d);
dx[++cntx]=a-1,dy[++cnty]=b-1,dx[++cntx]=c,dy[++cnty]=d;
++k;
q[++m]={a-1,b-1,1,k};
q[++m]={a-1,d,-1,k};
q[++m]={c,b-1,-1,k};
q[++m]={c,d,1,k};
}
scanf("%d",&op);
}
std::sort(dx+1,dx+1+cntx);
std::sort(dy+1,dy+1+cnty);
cntx=std::unique(dx+1,dx+1+cntx)-dx-1;
cnty=std::unique(dy+1,dy+1+cnty)-dy-1;
for(int i=1;i<=m;i++)
{
q[i].a=std::lower_bound(dx+1,dx+1+cntx,q[i].a)-dx;
q[i].b=std::lower_bound(dy+1,dy+1+cnty,q[i].b)-dy;
}
CDQ(1,m);
for(int i=1;i<=k;i++) printf("%d\n",ans[i]);
return 0;
}
2018.11.27