1. 程式人生 > >B1818 [Cqoi2010]內部白點 樹狀數組

B1818 [Cqoi2010]內部白點 樹狀數組

math 包含 永不 code struct 存在 個數 getchar() 但是

這個題的想法很好想,就是進行排序之後直接檢查每個點的上下左右是否有黑點就行.但是直接枚舉顯然不行,那怎麽辦呢?我們就用樹狀數組維護掃描線,把每排左右點看成一條線覆蓋,然後從下往上掃,遇到下加一,遇到上減一並記錄答案.這樣用掃描線維護就行了.

題幹:

Description
無限大正方形網格裏有n個黑色的頂點,所有其他頂點都是白色的(網格的頂點即坐標為整數的點,又稱整點)。每秒鐘,所有內部白點同時變黑,直到不存在內部白點為止。你的任務是統計最後網格中的黑點個數。 內部白點的定義:一個白色的整點P(x,y)是內部白點當且僅當P在水平線的左邊和右邊各至少有一個黑點(即存在x1 < x < x2使得(x1,y)和(x2,y)都是黑點),且在豎直線的上邊和下邊各至少有一個黑點(即存在y1 < y < y2使得(x,y1)和(x,y2)都是黑點)。
Input
輸入第一行包含一個整數n,即初始黑點個數。以下n行每行包含兩個整數(x,y),即一個黑點的坐標。沒有兩個黑點的坐標相同,坐標的絕對值均不超過109。
Output
輸出僅一行,包含黑點的最終數目。如果變色過程永不終止,輸出
-1。 Sample Input 4 0 2 2 0 -2 0 0 -2 Sample Output 5 數據範圍 36%的數據滿足:n < = 500 64%的數據滿足:n < = 30000 100%的數據滿足:n < = 100000

代碼:

#include<iostream>
#include<cstdio>
#include<cmath>
#include<ctime>
#include<queue>
#include<algorithm>
#include<cstring>
using
namespace std; #define duke(i,a,n) for(int i = a;i <= n;i++) #define lv(i,a,n) for(int i = a;i >= n;i--) #define clean(a) memset(a,0,sizeof(a)) const int INF = 1 << 30; typedef long long ll; typedef double db; template <class T> void read(T &x) { char c; bool op = 0
; while(c = getchar(), c < 0 || c > 9) if(c == -) op = 1; x = c - 0; while(c = getchar(), c >= 0 && c <= 9) x = x * 10 + c - 0; if(op) x = -x; } template <class T> void write(T x) { if(x < 0) putchar(-), x = -x; if(x >= 10) write(x / 10); putchar(0 + x % 10); } struct point { int x,y; }a[100010]; struct seg { int k,x,y,r; }s[1000010]; int n; int hsh[100010],cnt = 0; int tr[100010],ans = 0; bool cmp1(point a,point b) { if(a.x == b.x) return a.y < b.y; else return a.x < b.x; } bool cmp2(point a,point b) { if(a.y == b.y) return a.x < b.x; else return a.y < b.y; } bool cmp3(seg a,seg b) { if(a.y == b.y) return a.k < b.k; else return a.y < b.y; } int find(int x) { int l = 1,r = n,mid; while(l <= r) { int mid = (l + r) >> 1; if(hsh[mid] < x) l = mid + 1; else if(hsh[mid] > x) r = mid - 1; else return mid; } } void insert(int k,int l,int r,int t) { if(!k) { s[++cnt].x = find(l); s[cnt].r = find(r); s[cnt].y = t; } else { s[++cnt].x = find(t); s[cnt].y = l; s[cnt].k = 1; s[++cnt].x = find(t); s[cnt].y = r; s[cnt].k = -1; } } int lowbit(int x) { return x & -x; } void build() { sort(a + 1,a + n + 1,cmp1); duke(i,2,n) { if(a[i].x == a[i - 1].x) insert(1,a[i - 1].y,a[i].y,a[i].x); } sort(a + 1,a + n + 1,cmp2); duke(i,2,n) { if(a[i].y == a[i - 1].y) insert(0,a[i - 1].x,a[i].x,a[i].y); } } void update(int x,int y) { while(x <= n) { tr[x] += y; x += lowbit(x); } } int ask(int x) { int s = 0; while(x) { s += tr[x]; x -= lowbit(x); } return s; } void work() { duke(i,1,cnt) { if(!s[i].k) ans += ask(s[i].r - 1) - ask(s[i].x); else update(s[i].x,s[i].k); } } int main() { read(n); duke(i,1,n) { read(a[i].x); read(a[i].y); hsh[i] = a[i].x; } sort(hsh + 1,hsh + n + 1); build(); sort(s + 1,s + cnt + 1,cmp3); work(); printf("%d\n",ans + n); return 0; } /* 4 0 2 2 0 -2 0 0 -2 */

B1818 [Cqoi2010]內部白點 樹狀數組