P2163 [SHOI2007]园丁的烦恼(二维数点模板题)
生活随笔
收集整理的這篇文章主要介紹了
P2163 [SHOI2007]园丁的烦恼(二维数点模板题)
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
P2163 [SHOI2007]園丁的煩惱
題意:
在一個二維平面內有一些點,給你一個左上角和右下角的點,問這個范圍內有多少點
題解:
二維數點模板題
我們設F(a,b)表示以(0,0)為左下角,(a,b)為右上角的矩陣內有多少點
如圖不難得到:
黑色部分為=F(c,d)+F(a-1,b-1)-F(a-1,d)-F(c,b-1)
(不就是二維前綴和)
因為數據范圍過大,所以橫縱坐標都離散化處理。
現在我們如何求(0,0)到(x,y)內點的數量
我們把矩陣內的點看作是插入操作,相當于在矩陣中(x,y)位置+1.
把所有插入操作和查詢操作以x坐標為第一關鍵字,y坐標為第二關鍵字排序
若第i個是查詢操作,僅有[1,i-1]中的插入操作能影響它,因為第i個操作后面的操作坐標都比它大
同樣第i個操作是插入操作,不會影響到前面的查詢
這樣就利用樹狀數組實現二維數點問題
CDQ也可以二維數點,也是模板題
主席樹也可以二維數點,這里有詳細講解
代碼:
樹狀數組代碼:
#include<stdio.h> #include<cstring> #include<algorithm> #include<math.h> #include<vector> #define re register int #define rl register ll #define lowbit(x) x&(-x) using namespace std; typedef long long ll; int read() {re x=0,f=1;char ch=getchar();while(ch<'0' || ch>'9') {if(ch=='-') f=-1;ch=getchar();}while(ch>='0' && ch<='9') {x=10*x+ch-'0';ch=getchar();}return x*f; } inline void write(int x) {if(x>9) write(x/10);putchar(x%10+'0'); } inline char GetChar() {char ch=getchar();while(ch!='A' && ch!='B' && ch!='C') ch=getchar();return ch; }const int Size=500005; int n,m,tot,maxn,ny[Size*5]; struct zyd {int id,x,y,k,dt; } Q[Size*5]; inline void Push(int x,int y,int k,int id) {Q[++tot].x=x;Q[tot].y=y;Q[tot].k=k;Q[tot].id=id;Q[tot].dt=tot; } inline bool comp(zyd jzm,zyd xjp) {if(jzm.x!=xjp.x) return jzm.x<xjp.x;if(jzm.y!=xjp.y) return jzm.y<xjp.y;return jzm.dt<xjp.dt; } int tree[Size]; inline void update(int x) {for(re i=x; i<=maxn; i+=lowbit(i)) {tree[i]++;} } inline int query(int x) {int ans=0;for(re i=x; i; i-=lowbit(i)) {ans+=tree[i];}return ans; } int out[Size]; void solve() {n=read();m=read();for(re i=1; i<=n; i++) {int x=read();int y=read();Push(x,y,0,0);}for(re i=1; i<=m; i++) {int a=read();int b=read();int c=read();int d=read();Push(c,d,1,i);Push(a-1,b-1,1,i);Push(a-1,d,-1,i);Push(c,b-1,-1,i);}sort(Q+1,Q+1+tot,comp);for(re i=1; i<=tot; i++) {ny[i]=Q[i].y;}sort(ny+1,ny+1+tot);maxn=unique(ny+1,ny+1+tot)-(ny+1);for(re i=1; i<=tot; i++) {Q[i].y=lower_bound(ny+1,ny+1+maxn,Q[i].y)-ny;}for(re i=1; i<=tot; i++) {if(!Q[i].k) {update(Q[i].y);} else if(Q[i].k==1) {out[Q[i].id]+=query(Q[i].y);} else {out[Q[i].id]-=query(Q[i].y);}}for(re i=1; i<=m; i++) {printf("%d\n",out[i]);} }int main() {solve();return 0; }CDQ代碼:
#include<bits/stdc++.h> #define maxn 5000005 * 5 using namespace std; inline int read() {char x = getchar();int lin = 0, f = 1;while(x < '0' || x > '9'){if(x == '-') f = -1;x = getchar();}while(x >= '0' && x <= '9'){lin = lin * 10 + x - '0';x = getchar();}return lin * f; } struct st{int x,y,typ,add,id,ans; }s[maxn],ce[maxn]; int n,m,x,y,tot,a,b,c,d,ans[maxn]; void add(int x,int y,int typ,int add,int id,int ans) {s[++tot] = (st) {x,y,typ,add,id,ans}; } bool com(st a,st b) {if(a.x == b.x)if(a.y == b.y)return a.typ < b.typ;else return a.y < b.y;return a.x < b.x; } void cdq(int l,int r) {if(l == r) return;int mid = l + r >> 1;cdq(l,mid);cdq(mid + 1,r);int le = l,re = mid + 1,pos = 0,ans = 0;while(le <= mid || re <= r){if(re > r || (le <= mid && s[le].y <= s[re].y)){if(s[le].typ == 1) ++ans;ce[++pos] = s[le++];}else{if(s[re].typ == 2) s[re].ans += ans;ce[++pos] = s[re++];}}for(int i = 1; i <= pos; i++)s[l + i - 1] = ce[i]; }int main(){n = read(); m = read();for(int i = 1; i <= n; i++){x = read(); y = read();add(x,y,1,0,0,0);}for(int i = 1; i <= m; i++){a = read(); b = read();c = read(); d = read();add(a - 1,b - 1,2,1,i,0);add(c,d,2,1,i,0);add(a - 1,d,2,-1,i,0);add(c,b - 1,2,-1,i,0);}sort(s + 1,s + 1 + tot,com);cdq(1,tot);for(int i = 1; i <= tot; i++)if(s[i].typ == 2)ans[s[i].id] += s[i].add * s[i].ans;for(int i = 1; i <= m; i++)printf("%d\n",ans[i]); }總結
以上是生活随笔為你收集整理的P2163 [SHOI2007]园丁的烦恼(二维数点模板题)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: NAS入门之——Windows下添加My
- 下一篇: top命令源码分析