[ C q o i 2010 ] 内 部 白 点 [Cqoi2010]内部白点 [Cqoi2010]内部白点
Description:
- 无限大正方形网格里有n个黑色的顶点,所有其他顶点都是白色的(网格的顶点即坐标为整数的点,又称整点)。每秒钟,所有内部白点同时变黑,直到不存在内部白点为止。你的任务是统计最后网格中的黑点个数。 内部白点的定义:一个白色的整点P(x,y)是内部白点当且仅当P在水平线的左边和右边各至少有一个黑点(即存在x1 < x < x2使得(x1,y)和(x2,y)都是黑点),且在竖直线的上边和下边各至少有一个黑点(即存在y1 < y < y2使得(x,y1)和(x,y2)都是黑点)。
Input Format:
- 输入第一行包含一个整数n,即初始黑点个数。以下n行每行包含两个整数(x,y),即一个黑点的坐标。没有两个黑点的坐标相同,坐标的绝对值均不超过109。
Output Format:
- 输出仅一行,包含黑点的最终数目。如果变色过程永不终止,输出-1。
Sample Input:
- 4
0 2
2 0
-2 0
0 -2
Sample Output:
- 5
Tips:
- 36%的数据满足:n < = 500
64%的数据满足:n < = 30000
100%的数据满足:n < = 100000
TJ:
扫描线+树状数组优化处理,其实不会出现无法停止的情况,并且最多只要1秒就可以把所有可以改变的白点变成黑点。
可以发现由白点转化过来的黑点对结果没有影响,因为转化过来的黑点所在的行列上都已经有其他点了(否则这个黑点是怎么转化过来的),所以只要考虑初始给的黑点就行了。
因为每个点的坐标<=1e9所以首先对横坐标和纵坐标分别进行离散化。因为不存在某个横坐标那整一行都不会有白点变成黑点。
记录每一行的每个点出现的最高位置,必须要这一行的上下边都有点才行。当遇到某一行的某个位置第一次出现这个点的时候,就在树状数组的这个位置上+1,最后一次出现的时候树状数组的这个位置上就-1。
将所有点按一个坐标的大小排序,大小相同时按另一个坐标的大小,然后扫描线按行处理就行了。
CODE
#include<bits/stdc++.h>
using namespace std;
const int MAXN = 1e5+7;
#define All(v) v.begin(),v.end()
struct NODE{
int x,y;
bool operator <(const NODE &o) const{
if(x==o.x) return y<o.y;
else return x<o.x;
}
}node[MAXN];
int n;
vector<int> vecx,vecy;
int top[MAXN];
bool appear[MAXN];
int GetID(vector<int> &vec,int x){ return lower_bound(All(vec),x)-vec.begin()+1; }
void preprocess(){
sort(All(vecx)); sort(All(vecy));
vecx.erase(unique(All(vecx)),vecx.end());
vecy.erase(unique(All(vecy)),vecy.end());
memset(top,255,sizeof(top));
for(int i=1;i<=n;i++){
node[i].x = GetID(vecx,node[i].x);
node[i].y = GetID(vecy,node[i].y);
}
sort(node+1,node+1+n);
for(int i=1;i<=n;i++) top[node[i].y]=max(top[node[i].y],node[i].x);
}
struct Binary_Indexed_Tree{
int A[MAXN];
inline int lowbit(int x){ return x&-x; }
void modify(int pos,int x){
while(pos<MAXN){
A[pos]+=x;
pos+=lowbit(pos);
}
}
int query(int pos){
int res = 0;
while(pos){
res+=A[pos];
pos-=lowbit(pos);
}
return res;
}
}BIT;
int work(){
vector<NODE> pool;
int ans = 0;
for(int i=1;i<=n;i++){
if(node[i].x==node[i+1].x) pool.push_back(node[i]);
else{
pool.push_back(node[i]);
int l = pool[0].y;
int r = pool[pool.size()-1].y;
ans+=BIT.query(r)-BIT.query(l-1);
for(int j=0;j<(int)pool.size();j++){
if(!appear[pool[j].y]) ans++;
if(top[pool[j].y]!=pool[j].x){
if(!appear[pool[j].y]) BIT.modify(pool[j].y,1);
appear[pool[j].y] = 1;
}
else{
if(appear[pool[j].y]) BIT.modify(pool[j].y,-1);
appear[pool[j].y] = 0;
}
}
pool.clear();
}
}
return ans;
}
void check(){
#ifndef ONLINE_JUDGE
freopen("1818/4.out","r",stdin);
int ans;
scanf("%d",&ans);
puts(ans==work()?"True":"False");
#endif
return;
}
int main(){
#ifndef ONLINE_JUDGE
freopen("1818/4.in","r",stdin);
#endif
scanf("%d",&n);
for(int i=1;i<=n;i++){
scanf("%d %d",&node[i].x,&node[i].y);
vecx.push_back(node[i].x);
vecy.push_back(node[i].y);
}
preprocess();
check();
//printf("%d\n",work());
return 0;
}