1. 程式人生 > >[Luogu4390][BOI2007]Mokia 摩基亞

[Luogu4390][BOI2007]Mokia 摩基亞

names for cst show problem amp source nod https

luogu

題意

支持平面內單點加一個值以及矩陣求和。
平面大小\(W\le2*10^6\),修改操作\(\le1.6*10^5\),查詢操作\(\le10^4\)

sol

\(CDQ\)寫一發。
把一個詢問拆成四個點,類似二維前綴和的形式。這樣對於每一個詢問,相當於就是問滿足\(x_i\le X,y_i\le Y\)的權值和。
樹狀數組維護即可。

code

#include<cstdio>
#include<algorithm>
using namespace std;
int gi()
{
    int x=0,w=1;char ch=getchar();
    while
((ch<'0'||ch>'9')&&ch!='-') ch=getchar(); if (ch=='-') w=0,ch=getchar(); while (ch>='0'&&ch<='9') x=(x<<3)+(x<<1)+ch-'0',ch=getchar(); return w?x:-x; } const int N = 2e6+5; struct node{ int id,x,y,v,opt; bool
operator < (const node &b) const { if (x!=b.x) return x<b.x; if (y!=b.y) return y<b.y; return !opt; } }p[N],q[N]; int W,n,m,c[N],ans[N]; void modify(int k,int v){while(k<=W)c[k]+=v,k+=k&-k;} int query(int k){int s=0;while(k)s+=c[k],k-=k&-k;return
s;} void CDQ(int l,int r) { if (l==r) return; int mid=l+r>>1;CDQ(l,mid);CDQ(mid+1,r); int L=l,R=mid+1; for (int i=l;i<=r;++i) if (L<=mid&&(R>r||p[L]<p[R])) { q[i]=p[L++]; if (!q[i].opt) modify(q[i].y,q[i].v); } else { q[i]=p[R++]; if (q[i].opt) ans[q[i].v]+=query(q[i].y)*q[i].opt; } for (int i=l;i<=r;++i) { p[i]=q[i]; if (p[i].id<=mid&&!p[i].opt) modify(q[i].y,-q[i].v); } } int main() { while (233) { int opt=gi(); if (opt==0) W=gi(); if (opt==1) { int x=gi(),y=gi(),v=gi(); p[++n]=(node){n,x,y,v,0}; } if (opt==2) { int x1=gi(),y1=gi(),x2=gi(),y2=gi(); ++m; if (x1>1&&y1>1) p[++n]=(node){n,x1-1,y1-1,m,1}; if (x1>1) p[++n]=(node){n,x1-1,y2,m,-1}; if (y1>1) p[++n]=(node){n,x2,y1-1,m,-1}; p[++n]=(node){n,x2,y2,m,1}; } if (opt==3) break; } CDQ(1,n); for (int i=1;i<=m;++i) printf("%d\n",ans[i]); return 0; }

[Luogu4390][BOI2007]Mokia 摩基亞