zoukankan      html  css  js  c++  java
  • P5816 [CQOI2010]内部白点

    题目描述

    无限大正方形网格里有(n)个黑色的顶点,所有其他顶点都是白色的(网格的顶点即坐标为整数的点,又称整点)。每秒钟,所有内部白点同时变黑,直到不存在内部白点为止。你的任务是统计最后网格中的黑点个数。

    内部白点的定义:一个白色的整点(P(x,y))是内部白点当且仅当(P)在水平线的左边和右边各至少有一个黑点(即存在(x_1 < x < x_2)使得((x_1,y))((x_2,y))都是黑点),且在竖直线的上边和下边各至少有一个黑点(即存在(y_1 < y < y_2)使得((x,y_1))((x,y_2))都是黑点)。

    题解

    我们首先对所有的点按照以纵坐标为第一关键字从大到小,以横坐标为第二关键字从小到大排序,然后对横坐标进行离散化。

    我们预处理出来对于每一个横坐标它的纵坐标的上界和下界。

    然后按顺序扫所有的点,用线段树维护一个横坐标是否可行,如果该点的纵坐标是某个横坐标的上界就在这个横坐标处加一,如果是下界就减一。

    当换行时我们统计一下该行的贡献即可。

    详见代码。

    #include <iostream>
    #include <cstdio>
    #include <algorithm>
    #define ll long long
    using namespace std;
    const int N = 1e5 + 5;
    const int inf = 0x3f3f3f3f;
    int n, tr[N << 2], b[N], len, up[N], down[N], L;
    ll ans;
    struct node{int x, y;}d[N];
    inline int read()
    {
    	int x = 0, f = 1; char ch = getchar();
    	while(ch < '0' || ch > '9') {if(ch == '-') f = -1; ch = getchar();}
    	while(ch >= '0' && ch <= '9') {x = (x << 3) + (x << 1) + (ch ^ 48); ch = getchar();}
    	return x * f;
    }
    bool cmp(const node & a, const node & b) {return a.y == b.y ? a.x < b.x : a.y > b.y;}
    void change(int k, int l, int r, int x, int val)
    {
    	if(l == r) return tr[k] += val, void();
    	int mid = (l + r) >> 1;
    	if(x <= mid) change(k << 1, l, mid, x, val);
    	else change(k << 1 | 1, mid + 1, r, x, val);
    	tr[k] = tr[k << 1] + tr[k << 1 | 1];
    }
    int query(int k, int l, int r, int x, int y)
    {
    	if(x <= l && r <= y) return tr[k];
    	int mid = (l + r) >> 1, ans = 0;
    	if(x <= mid) ans += query(k << 1, l, mid, x, y);
    	if(y > mid) ans += query(k << 1 | 1, mid + 1, r, x, y);
    	return ans;
    }
    void work()
    {
    	n = read();
    	for(int i = 1; i <= n; i ++)
    	{
    		b[i] = d[i].x = read(); d[i].y = read();
    		up[i] = -inf; down[i] = inf;
    	}
    	sort(d + 1, d + n + 1, cmp);
    	sort(b + 1, b + n + 1); len = unique(b + 1, b + n + 1) - b - 1;
    	for(int i = 1; i <= n; i ++)
    	{
    		d[i].x = lower_bound(b + 1, b + len + 1, d[i].x) - b;
    		up[d[i].x] = max(up[d[i].x], d[i].y);
    		down[d[i].x] = min(down[d[i].x], d[i].y);
    	}
    	L = d[1].x; d[n + 1].y = inf;//·ÀÖ¹d[n].y = 0; 
    	for(int i = 1; i <= n; i ++)
    	{
    		if(d[i].y == up[d[i].x]) change(1, 1, len, d[i].x, 1);
    		if(d[i].y == down[d[i].x]) ans ++, change(1, 1, len, d[i].x, -1);//²»ÄÜelse
    		if(d[i].y != d[i + 1].y)
    		{
    			ans += query(1, 1, len, L, d[i].x);
    			L = d[i + 1].x;
    		}
    	}
    	printf("%lld
    ", ans);
    }
    int main() {return work(), 0;}
    
  • 相关阅读:
    SpreadJS 复制行
    RookeyFrame 模块 线上创建的模块 迁移到 线下来
    RookeyFrame 附件 上传附件
    RookeyFrame 字典 新增和绑定
    RookeyFrame Bug 表单管理 -> 查看表单 ->编辑字段页面 JS报错
    Catalan数
    美元汇率
    5倍经验日
    二分查找的边界问题
    线段覆盖5
  • 原文地址:https://www.cnblogs.com/Sunny-r/p/12692675.html
Copyright © 2011-2022 走看看