poj 3109 树状数组加扫描线
传送门:https://vjudge.net/problem/POJ-3109
题意:给你一个无限大的棋盘,给你n个黑色点的坐标,然后一个白色点会变成黑色点的条件是 白色点的上下左右都有黑色点。问你最后棋盘上黑色点的个数。
《挑战程序设计竞赛》上来的。
由于坐标达到1e9,n只有1e5,所以对点坐标离散化。然后记录每一个横轴的左右端点(yl和yr)。然后对每一个纵轴都记录该纵轴上的点的y值(xnod),最后按x轴从左到右扫,比如说扫到了这个纵轴,再按照y值从小到大枚举,统计sum(xnod[i][j]-1)-sum(xnod[i][j-1]),其中xnod[i]表示第i位的纵轴,xnod[i][j]表示第i位纵轴的第j位y值,sum是树状数组,sum(a)表示的是有多少条横线的y值是<=a的。
其中sum(xnod[i][j]-1)-sum(xnod[i][j-1]),就保证了树状数组所统计的,只会是黑点之间的要变成黑点的白点,所以不会算多,因此答案要加上原来给的n个黑点。
由于每个点只会枚举一次,树状数组logn级别,所以时间复杂度O(nlogn),能过。
最后就是扫描线的常规做法了,横轴的左端点就在树状数组+1,右端点就-1,。
然后留意如果yl[i]==yr[i],也就是说y值排第i位的那个”线“左右端点同,也就是只是一个点,构不成一条线,这时候就不要加减点了。然后用vis数组标记一下该横轴是否已经被统计进树状数组了。防止一横轴上有多于两个点的情况。
最后,喜闻乐见的上代码。
1 // Cease to struggle and you cease to live 2 #include <iostream> 3 #include <cmath> 4 #include <cstdio> 5 #include <cstring> 6 #include <algorithm> 7 #include <queue> 8 #include <vector> 9 #include <set> 10 #include <map> 11 #include <stack> 12 using namespace std; 13 typedef long long ll; 14 const int N=1e5+8; 15 struct node{ 16 int x,y; 17 }a[N]; 18 int X[N],Y[N]; 19 int yl[N],yr[N]; 20 vector<int> xnod[N]; 21 bool vis[N]; 22 int tr[N]; 23 int n,nx,ny; 24 void add(int x,int v){ 25 for(;x<=ny;x+=x&-x) tr[x]+=v; 26 } 27 int sum(int x){ 28 int res=0; 29 for(;x;x-=x&-x) res+=tr[x]; 30 return res; 31 } 32 int main(){ 33 scanf("%d",&n); 34 memset(yl,0x3f3f3f3f,sizeof(yl)); 35 memset(yr,-0x3f3f3f3f,sizeof(yr)); 36 for(int i=1;i<=n;++i){ 37 scanf("%d%d",&a[i].x,&a[i].y); 38 X[i]=a[i].x; 39 Y[i]=a[i].y; 40 } 41 sort(X+1,X+1+n); 42 sort(Y+1,Y+1+n); 43 nx=unique(X+1,X+1+n)-X-1; 44 ny=unique(Y+1,Y+1+n)-Y-1; 45 for(int i=1;i<=n;++i){ 46 int px=lower_bound(X+1,X+1+nx,a[i].x)-X; 47 int py=lower_bound(Y+1,Y+1+ny,a[i].y)-Y; 48 xnod[px].push_back(py); 49 yl[py]=min(yl[py],px); 50 yr[py]=max(yr[py],px); 51 } 52 for(int i=1;i<=nx;++i) sort(xnod[i].begin(),xnod[i].end()); 53 int ans=0; 54 for(int i=1;i<=nx;++i){ 55 int num=xnod[i].size(); 56 for(int j=1;j<num;++j){ 57 ans+=sum(xnod[i][j]-1)-sum(xnod[i][j-1]); 58 } 59 for(int j=0;j<num;++j){ 60 int nowy=xnod[i][j]; 61 if(yl[nowy]==yr[nowy]) continue; 62 if(yl[nowy]==i && vis[nowy]==0){ 63 vis[nowy]=1; 64 add(nowy,1); 65 } 66 else if(yr[nowy]==i && vis[nowy]){ 67 vis[nowy]=0; 68 add(nowy,-1); 69 } 70 } 71 } 72 printf("%d",ans+n); 73 return 0; 74 }