bzoj 1818 [CQOI 2010] 内部白点 - 扫描线 - 树状数组

题目传送门

  快速的列车

  慢速的列车

题目大意

  一个无限大的方格图内有$n$个黑点。问有多少个位置上下左右至少有一个黑点或本来是黑点。

  扫描线是显然的。

  考虑一下横着的线段,取它两个端点,横坐标小的地方放一个+1,大的地方放一个-1事件。

  然后扫描,扫到的横着的线段更新,竖着的线段用树状数组求答案。

  然后考虑这一列上原来存在的黑点有没有被统计,如果没有就加上。

Code

  1 /**
  2  * bzoj
  3  * Problem#1818
  4  * Accepted
  5  * Time: 1824ms
  6  * Memory: 9776k
  7  */
  8 #include <algorithm>
  9 #include <iostream>
 10 #include <cstdlib>
 11 #include <cstring>
 12 #include <cstdio>
 13 #include <vector>
 14 #ifndef WIN32
 15 #define Auto "%lld"
 16 #else
 17 #define Auto "%I64d"
 18 #endif
 19 using namespace std;
 20 #define smax(a, b) (a = max(a, b))
 21 #define smin(a, b) (a = min(a, b))
 22 typedef bool boolean;
 23 #define ll long long
 24
 25 const int N = 1e5 + 5;
 26
 27 typedef class IndexedTree {
 28     public:
 29         int s;
 30         int* ar;
 31
 32         IndexedTree() {    }
 33         IndexedTree(int s):s(s) {
 34             ar = new int[(s + 1)];
 35             memset(ar, 0, sizeof(int) * (s + 1));
 36         }
 37
 38         void add(int idx, int val) {
 39             for ( ; idx <= s; idx += (idx & (-idx)))
 40                 ar[idx] += val;
 41         }
 42
 43         int query(int idx) {
 44             int rt = 0;
 45             for ( ; idx; idx -= (idx & (-idx)))
 46                 rt += ar[idx];
 47             return rt;
 48         }
 49 }IndexedTree;
 50
 51 typedef class Event {
 52     public:
 53         int x, y, val;
 54
 55         Event(int x = 0, int y = 0, int val = 0):x(x), y(y), val(val) {    }
 56
 57         boolean operator < (Event b) const {
 58             return x < b.x;
 59         }
 60 }Event;
 61
 62 int n;
 63 int xs[N], ys[N], bxs[N], bys[N];
 64 int ls[N], rs[N], us[N], ds[N];
 65 ll res = 0;
 66 int tp = 0;
 67 Event es[N << 1];
 68 vector<int> vs[N];
 69 IndexedTree it;
 70
 71 inline void init() {
 72     scanf("%d", &n);
 73     for (int i = 1; i <= n; i++)
 74         scanf("%d%d", xs + i, ys + i);
 75 }
 76
 77 inline void descrete(int* ar, int* br, int n) {
 78     memcpy(br, ar, sizeof(int) * (n + 1));
 79     sort(br + 1, br + n + 1);
 80     for (int i = 1; i <= n; i++)
 81         ar[i] = lower_bound(br + 1, br + n + 1, ar[i]) - br;
 82 }
 83
 84 inline void solve() {
 85     descrete(xs, bxs, n);
 86     descrete(ys, bys, n);
 87
 88     for (int i = 1; i <= n; i++)
 89         ls[i] = ds[i] = N;
 90     for (int i = 1; i <= n; i++)
 91         us[i] = rs[i] = 0;
 92
 93     for (int i = 1; i <= n; i++) {
 94         smin(ls[ys[i]], xs[i]);
 95         smax(rs[ys[i]], xs[i]);
 96         smin(ds[xs[i]], ys[i]);
 97         smax(us[xs[i]], ys[i]);
 98     }
 99
100     for (int i = 1; i <= n; i++)
101         vs[xs[i]].push_back(ys[i]);
102
103     for (int i = 1; i <= n; i++)
104         if (ls[i] < rs[i] - 1) {
105             es[++tp] = Event(ls[i], i, 1);
106             es[++tp] = Event(rs[i], i, -1);
107         }
108     sort(es + 1, es + tp + 1);
109
110     int pe = 1;
111     it = IndexedTree(n);
112     bxs[0] = -1e9 - 5;
113     for (int i = 1; i <= n; i++) {
114         if (bxs[i] == bxs[i - 1])    continue;
115         while (pe <= tp && es[pe].x == i)
116             it.add(es[pe].y, es[pe].val), pe++;
117         if (ds[i] <= us[i])
118             res += it.query(us[i]) - it.query(ds[i] - 1);//, cerr << bxs[i] << endl;
119         for (int j = 0; j < (signed) vs[i].size(); j++)
120             if (it.query(vs[i][j]) - it.query(vs[i][j] - 1) == 0)
121                 res++;
122 //        cerr << bxs[i] << " " << res << endl;
123     }
124     printf(Auto"\n", res);
125 }
126
127 int main() {
128     init();
129     solve();
130     return 0;
131 }

原文地址:https://www.cnblogs.com/yyf0309/p/9393016.html

时间: 2024-10-11 00:03:36

bzoj 1818 [CQOI 2010] 内部白点 - 扫描线 - 树状数组的相关文章

【BZOJ1818】[Cqoi2010]内部白点 扫描线+树状数组

[BZOJ1818][Cqoi2010]内部白点 Description 无限大正方形网格里有n个黑色的顶点,所有其他顶点都是白色的(网格的顶点即坐标为整数的点,又称整点).每秒钟,所有内部白点同时变黑,直到不存在内部白点为止.你的任务是统计最后网格中的黑点个数. 内部白点的定义:一个白色的整点P(x,y)是内部白点当且仅当P在水平线的左边和右边各至少有一个黑点(即存在x1 < x < x2使得(x1,y)和(x2,y)都是黑点),且在竖直线的上边和下边各至少有一个黑点(即存在y1 <

BZOJ 1818 内部白点(离散化+树状数组)

此题就是1227 的弱化版. 画个图或者稍微证明一下就能够知道,一定不会超过一次变换. 那么我们只需要统计有多少个白点会变黑,换句话说就是有多少个白点上下左右都有黑点. 离散化横坐标,因为没有黑点在的列是没有任何意义的,对答案也没有贡献. 然后处理每一行,对于每一行,维护一个BIT也就是哪些点会产生贡献,这个BIT最多只会有n次修改,n次查询. 所以时间复杂度为O(nlogn). # include <cstdio> # include <cstring> # include &l

BZOJ 1452: [JSOI2009]Count (二维树状数组)

Description Input Output Sample Input Sample Output 1 2 HINT 二维树状数组的简单应用,c数组的第一维坐标相当于哈希.如果是修改操作,修改前 将当前的值的个数以及祖先都减1, 修改后将个数加1. #include <iostream> #include <cstring> #include <cstdio> #include <cmath> #include <set> #include

[扫描线+树状数组]解决矩形包含点的问题

今天做到第二题,大部分的思路都理解了之后最后剩下一个问题 zzx:“然后扫描线+树状数组搞一下就好了” 看到这两个算法就产生了一种我肯定会的错觉... 然后后来发现并不会的时候很惭愧... 然后十分感谢YDC,在之前完全陌生的情况下 我去问这样一个问题 超级超级超级耐心地给我解答  我问着每一个他们看起来显然的具体处理方法 突然发现真的像张老师说的:“你普及升提高的这条路没有怎么走,中间那块知识是空着的啊” 今天才切实体会到...但是或许正是这样今天学到这样的一个东西更让我觉得开心吧 树状数组解

【BZOJ】1012: [JSOI2008]最大数maxnumber(树状数组+区间最值)

http://www.lydsy.com/JudgeOnline/problem.php?id=1012 树状数组原来我只懂得sum和add的操作,今天才知道可以有求区间最值的操作,我学习了一下写了个,1a了. 区间最值其实和区间求和差不多,就是将sum数组的含义转移到max,然后通过特定的区间更新max. 在区间求和中,当我们维护max[i]的时候,要找到它前面所有的max[j]来更新,在这里因为是树状数组,所以可以降成一个log级,画图可知,max[i]需要的max只有max[i-2^0],

【BZOJ4009】[HNOI2015]接水果 DFS序+整体二分+扫描线+树状数组

[BZOJ4009][HNOI2015]接水果 Description 风见幽香非常喜欢玩一个叫做 osu!的游戏,其中她最喜欢玩的模式就是接水果.由于她已经DT FC 了The big black,  她觉得这个游戏太简单了,于是发明了一个更加难的版本.首先有一个地图,是一棵由 n 个顶点.n-1 条边组成的树(例如图 1给出的树包含 8 个顶点.7 条边).这颗树上有 P 个盘子,每个盘子实际上是一条路径(例如图 1 中顶点 6 到顶点 8 的路径),并且每个盘子还有一个权值.第 i 个盘子

FZU 2225 小茗的魔法阵 扫描线+树状数组

这个题和一个CF上的找"Z"的题差不多,都是扫描线+树状数组 从右上角的主对角线开始扫描,一直扫到左下角,每次更新,右延伸等于该扫描线的点,注意在其所在的树状数组更新就好了 时间复杂度O(n^2logn) #include <stdio.h> #include <iostream> #include <vector> #include <math.h> #include <set> #include <map> #

【bzoj4540】[Hnoi2016]序列 单调栈+离线+扫描线+树状数组区间修改

题目描述 给出一个序列,多次询问一个区间的所有子区间最小值之和. 输入 输入文件的第一行包含两个整数n和q,分别代表序列长度和询问数.接下来一行,包含n个整数,以空格隔开,第i个整数为ai,即序列第i个元素的值.接下来q行,每行包含两个整数l和r,代表一次询问. 输出 对于每次询问,输出一行,代表询问的答案. 样例输入 5 5 5 2 4 1 3 1 5 1 3 2 4 3 5 2 5 样例输出 28 17 11 11 17 题解 单调栈+离线+扫描线+树状数组区间修改 首先把使用单调栈找出每个

HDU - 5741 Helter Skelter 扫描线 + 树状数组

HDU - 5741 我们枚举段的起点和终点, 那么每一种情况0的范围是[lx, rx], 1的出现范围是[ly, ry], 可以在二维平面上用矩形表示. 然后问题就变成了询问点有没有被至少一个矩形覆盖, 扫描线 + 树状数组就可以了. #pragma GCC optimize(2) #pragma GCC optimize(3) #include<bits/stdc++.h> #define LL long long #define LD long double #define ull un