POJ 3109 Inner Vertices 树状数组

讲点无关的,发现之前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姿势行得通,速度也不会比这个快多少

以下今天水过代码,明天学扫描线!


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值