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 }
View Code

 

posted @ 2019-05-17 14:49  小布鞋  阅读(269)  评论(0编辑  收藏  举报