[bzoj1935][Shoi2007]Tree 園丁的煩惱 _樹狀數組

來源:互聯網
上載者:User

標籤:algorithm   $1   lin   void   def   二維樹狀數組   turn   表示   puts   

Tree 園丁的煩惱 bzoj-1935 Shoi-2007

題目大意:給定平面上的$n$個點,$m$次查詢矩形點個數。

注釋:$1\le n,m\le 5\cdot 10^5$。

想法:靜態二維數點。

$Orz Winniechen$,真tm敢寫$KD-Tree$,雖然$T$了..

正常這種靜態二維數點我們都要請到樹狀數組。最簡單的就是二維樹狀數組。

但是發現開不下,這樣的話我們依據它可以離線這一點,我們將每個詢問$(x1,y1)$到$(x2,y2)$變成$4$次查詢:

$(x1-1,y1-1),(x1-1,y2),(x2,y1-1),(x2,y2)$把它們哥四個都當成點放入點集。每次都相當於查詢$(1,1)$到$balabala$

每個點集中的點有$4$個參數:橫縱座標,種類和係數。

種類就是這個點到底是給定的點還是查詢的點。

係數的話就是容斥前面的係數:$(x1-1,y1-1)$和$(x2,y2)$前面是$1$,$(x1-1,y2)$和$(x2,y1-1)$前面是$-1$。

然後我們將點集排序,橫座標遞增為第一關鍵字,縱座標遞增為第二關鍵字。

緊接著我們順次枚舉每個點,如果這個點的種類是給定點,我們將它壓到樹狀數組裡。

是一個樹狀數組裡,我們只開一個樹狀數組,記錄的是小於每個橫座標的點的個數。

這樣的話根據我們的關鍵字可知,每一個有可能更新查詢的點都會被提前枚舉過。

如果這個點是查詢,就直接查詢然後累加到對應查詢的編號答案上,即可。

最後,附上醜陋的代碼... ...

#include <iostream>#include <cstdio>#include <cstring>#include <algorithm>#define N 1000010 using namespace std;struct Node{int x,y,f,id;//這裡跟上述的有些不一樣。//我們用f直接可以同時記錄種類和係數。如果f==0,那麼就表示這個點是給定的點,反之f=1或-1代表係數,直接累計即可。}q[N<<2];int tree[10000010];int mx=0;int ans[N];inline bool cmp(const Node &a,const Node &b){return a.x!=b.x?a.x<b.x:(a.y!=b.y?a.y<b.y:a.id<b.id);}int a,b,c,d;int cnt;inline int lowbit(int x) {return x&(-x);}void fix(int x){// if(!x) x++;// puts("fix");for(int i=x;i<=mx+1;i+=lowbit(i)){// printf("aha %d\n",i);tree[i]++;}}int query(int x){// puts("query");int ans=0;for(int i=x;i>=1;i-=lowbit(i)){ans+=tree[i];}return ans;}int main(){int n,m; cin >> n >> m ;for(int i=1;i<=n;i++){scanf("%d%d",&q[i].x,&q[i].y);q[i].x++,q[i].y++;mx=max(mx,q[i].y);}cnt=n;// puts("Fuck 1");for(int i=1;i<=m;i++){scanf("%d%d%d%d",&a,&b,&c,&d);c++,d++;q[++cnt].x=c; q[cnt].y=d; q[cnt].f=1; q[cnt].id=i;//這裡不要把係數搞錯q[++cnt].x=c; q[cnt].y=b; q[cnt].f=-1; q[cnt].id=i;q[++cnt].x=a; q[cnt].y=d; q[cnt].f=-1; q[cnt].id=i;q[++cnt].x=a; q[cnt].y=b; q[cnt].f=1; q[cnt].id=i;}// printf("Gun %d\n",cnt);// puts("Fuck 2");sort(q+1,q+cnt+1,cmp);for(int i=1;i<=cnt;i++){// printf("Shit %d\n",i);if(!q[i].id) fix(q[i].y);else ans[q[i].id]+=query(q[i].y)*q[i].f;//這就是直接壓到一個變數的好處,不用特判直接加就行了,反正如果是給定點f就是0,不會影響答案。}// puts("Fuck 3");for(int i=1;i<=m;i++){printf("%d\n",ans[i]);}return 0;}

小結:這個想法極其常用,很多靜態可離線二維數點問題都可以用這個來解決。那些動態就讓KD-Tree上吧,反正出了那種題被卡常的不可能只有你一個人/手動滑稽

[bzoj1935][Shoi2007]Tree 園丁的煩惱 _樹狀數組

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.