讲点无关的,发现之前BIT专题时我居然会二维的BIT……另外还水过了一道扫描线,那题目数据太小 ╮(╯-╰)╭
这道题大概前天刷挑战的时候刷到的吧,当时粗略看了下题目,没太懂题意,这个BIT能做?
今天特地给自己定了目标这道题一定要写出来,认真的想了想
--------以上废话----------------
关键点,绝对不可能不stop, 并且产生的点都是由最初的点产生而来的
坐标绝对值1e9先离散化不用说(埋下个坑)
对存在点的每一列,上端点纵坐标为up,下端点为down
在down-up这些行中 如果该列左边和右边都有点 那么这列的这个点就要变黑
主要矛盾就是解决有多少变黑的,然而会变黑的点本身就可能是黑的,不能重复计数
因此一开始的点数目干脆不算即可
每一行左端点lft, 右端点rght
/*对于每一列找出这一列左边有点和右边有点的行*/
#include <iostream>
#include <cstdio>
#include <map>
#include <vector>
#include <cstring>
#include <set>
#include <algorithm>
using namespace std;
const int maxn = 1e5 + 4;
int b[maxn], n, up[maxn], down[maxn], lft[maxn], rght[maxn], r[maxn], c[maxn], ir, ic, rows[maxn], columns[maxn];
vector<int> thisc[maxn];
inline void update(int pos, int k){
for (int i = pos; i < ir; i += (i & -i)) b[i] += k;
return;
}
inline int query(int pos){
int ans = 0;
for (int i = pos; i != 0; i -= (i & -i)) ans += b[i];
return ans;
}
int main(){
// ios::sync_with_stdio(false);
int i, j, k, kase;
while(~scanf("%d", &n)){
for (i = 1; i <= n; ++i){
scanf("%d%d", &r[i], &c[i]);
rows[i-1] = r[i];
columns[i-1] = c[i];
}
sort(rows, rows+n);
ir = unique(rows, rows+n) - rows;
sort(columns, columns+n);
ic = unique(columns, columns+n) - columns;
for (i = 1; i <= n; ++i){
r[i] = lower_bound(rows, rows+ir, r[i]) - rows + 1;
c[i] = lower_bound(columns, columns+ic, c[i]) - columns + 1;
}
++ir; ++ic;
memset(up, 0, sizeof up);
memset(down, 0x3f, sizeof down);
memset(lft, 0x3f, sizeof lft);
memset(rght, 0, sizeof rght);
for (i = 1; i < ic; ++i) thisc[i].clear();
for (i = 1; i <= n; ++i){
thisc[c[i]].push_back(r[i]);
rght[r[i]] = max(rght[r[i]], c[i]);
lft[r[i]] = min(lft[r[i]], c[i]);
up[c[i]] = max(up[c[i]], r[i]);
down[c[i]] = min(down[c[i]], r[i]);
}
memset(b, 0, sizeof b);
long long sum = 0;
for (i = 1; i < ic; ++i){
for (j = 0; j < thisc[i].size(); ++j)
if (lft[thisc[i][j]] == i && rght[thisc[i][j]] >= i) update(thisc[i][j], 1);
sum += 1LL * (query(up[i]) - query(down[i] - 1));
for (j = 0; j < thisc[i].size(); ++j)
if (rght[thisc[i][j]] == i && lft[thisc[i][j]] <= i) update(thisc[i][j], -1);
}
printf("%lld\n", sum);
}
return 0;
}
显然如果 (lft < 列标 || rght > 列标) 这个点就不会变黑
BIT维护对于目前这列有多少行会变黑
从第i列到第i+1列 改变的只有可能是第 i+1 列上有的点的那些行
在我的做法中对每个点要更新两次BIT 复杂度2nlogn
--------------------以下吐槽---------------------------
T到无语啊,统计了下我的复杂度总共大概10nlogn左右 单case 2s 总共5s想不通怎么T啊
各种看题解 大部分都说扫描线套路一发, 可能写题解的人和我一样主要是写给自己看的吧, 关键地方不知道他在说什么啊orz
百度扫描线,倒是找到一个详解的,尼玛英文3-5k words
找了一个代码短一点的,想直接看代码看下能不能领悟扫描线加线段树的做法,看到他的离散化
突然反应过来我的离散化写复杂了//也不能这样说,反正用了愚蠢的姿势
记一下离散化标准套路:sort -> unique(返回末位+1指针) -> 每个数lower_bound
就算map姿势行得通,速度也不会比这个快多少
以下今天水过代码,明天学扫描线!