B1818 [Cqoi2010]内部白点 树状数组
Posted dukelv
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了B1818 [Cqoi2010]内部白点 树状数组相关的知识,希望对你有一定的参考价值。
这个题的想法很好想,就是进行排序之后直接检查每个点的上下左右是否有黑点就行.但是直接枚举显然不行,那怎么办呢?我们就用树状数组维护扫描线,把每排左右点看成一条线覆盖,然后从下往上扫,遇到下加一,遇到上减一并记录答案.这样用扫描线维护就行了.
题干:
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 ",ans + n); return 0; } /* 4 0 2 2 0 -2 0 0 -2 */
以上是关于B1818 [Cqoi2010]内部白点 树状数组的主要内容,如果未能解决你的问题,请参考以下文章