UOJ#406/LOJ2864【IOI2018】排座位 线段树

Description
你要在一个长方形大厅里举办国际编程比赛,该大厅共有 H W HW HW 个座位( H H H W W W 列)。行的编号是从 0 0 0 H − 1 H-1 H1,列的编号是从 0 0 0 W − 1 W-1 W1。位于 r r r c c c 列的座位用 ( r , c ) (r,c) (r,c) 表示。一共邀请了 H W HW HW 位参赛者,编号是从 0 0 0 H W − 1 HW-1 HW1。你制定好了一个座位表,第 i i i 0 ≤ i ≤ H W − 1 0\le i\le HW-1 0iHW1)个参赛者被安排到座位 ( R i , C i ) (R_i,C_i) (Ri,Ci)。座位表中参赛者和座位是一一对应的。
大厅中一个座位集合 S S S 被称为是长方形的,如果存在整数 r 1 , r 2 , c 1 r_1,r_2,c_1 r1,r2,c1 c 2 c_2 c2 满足下列条件:
0 ≤ r 1 ≤ r 2 ≤ H − 1 0\le r_1\le r_2\le H-1 0r1r2H1
0 ≤ c 1 ≤ c 2 ≤ W − 1 0\le c_1\le c_2\le W-1 0c1c2W1
S S S 正好是所有满足 r 1 ≤ r ≤ r 2 r_1\le r\le r_2 r1rr2 c 1 ≤ c ≤ c 2 c_1\le c\le c_2 c1cc2 的座位 ( r , c ) (r,c) (r,c) 的集合。
如果一个长方形座位集合包含 k k k 1 ≤ k ≤ H W 1\le k\le HW 1kHW)个座位,并且被分配到这个集合的参赛者的编号恰好是从 0 0 0 k − 1 k-1 k1,那么该集合是美妙的。一个座位表的美妙度定义为这个表中美妙的长方形座位集合的个数。
在准备好座位表后,你会收到一些交换两个参赛者座位的请求。具体来说,有 Q Q Q 个这样的请求,按时间顺序编号为 0 0 0 Q − 1 Q-1 Q1。第 j j j 0 ≤ j ≤ Q − 1 0\le j\le Q-1 0jQ1)个请求希望交换参赛者 A j A_j Aj B j B_j Bj 的座位。你立即接受每个请求并更新座位表。每次更新后,你的目标是计算当前座位表的美妙度。


Sample Input
2 3 2
0 0
1 0
1 1
0 1
0 2
1 2
0 5
0 5


Sample Output
3
4


对于一个 k k k,我们将小于等于 k k k的值染成黑色,大于 k k k的值染成白色,那么就是询问有多少个 k k k满足构成了一个矩阵,且所有黑色构成了一个联通块。
对于构成了一个连通块就是相当于只存在一个黑点,它的左边和上边都是白点。
对于构成了矩阵,就是相当于不存在一个白点,它的上下左右的黑点数是两个以上。
第一种点的个数不会小于 1 1 1个,第二种点的个数不会小于 0 0 0个,那么只用看加起来是否等于 1 1 1即可。
这个东西你就相当于用线段树维护一个最小值以及最小值出现的次数。
每次的修改是常数次的(好像修改次数还挺多的,有十多次吧。。。


#include "seats.h"
#include <ctime>
#include <cstdio>
#include <vector>
#include <cstring>
#include <cstdlib>
#include <algorithm>

using namespace std;
typedef long long LL;
int _max(int x, int y) {return x > y ? x : y;}
int _min(int x, int y) {return x < y ? x : y;}
const int N = 1000001;
const int dx[4] = {0, -1, 0, 1};
const int dy[4] = {-1, 0, 1, 0};
int read() {
	int s = 0, f = 1; char ch = getchar();
	while(ch < '0' || ch > '9') {if(ch == '-') f = -1; ch = getchar();}
	while(ch >= '0' && ch <= '9') s = s * 10 + ch - '0', ch = getchar();
	return s * f;
}
void put(int x) {
	if(x >= 10) put(x / 10);
	putchar(x % 10 + '0');
}

struct tnode {
	int lc, rc, c, s, lazy;
} t[N * 2]; int cnt;
int n, m, g[N], R[N], C[N];
bool v[N];

void bt(int l, int r) {
	int now = ++cnt;
	t[now].lc = t[now].rc = -1;
	t[now].c = 0, t[now].s = (r - l + 1);
	t[now].lazy = 0;
	if(l < r) {
		int mid = (l + r) / 2;
		t[now].lc = cnt + 1; bt(l, mid);
		t[now].rc = cnt + 1; bt(mid + 1, r);
	}
}

void pushdown(int now) {
	if(!t[now].lazy) return ;
	int lc = t[now].lc, rc = t[now].rc;
	t[lc].c += t[now].lazy, t[lc].lazy += t[now].lazy;
	t[rc].c += t[now].lazy, t[rc].lazy += t[now].lazy;
	t[now].lazy = 0;
}

void update(int now) {
	int lc = t[now].lc, rc = t[now].rc;
	if(t[lc].c == t[rc].c) t[now].c = t[lc].c, t[now].s = t[lc].s + t[rc].s;
	else if(t[lc].c < t[rc].c) t[now].c = t[lc].c, t[now].s = t[lc].s;
	else t[now].c = t[rc].c, t[now].s = t[rc].s;
}

void change(int now, int l, int r, int ll, int rr, int c) {
	if(l == ll && r == rr) {t[now].c += c, t[now].lazy += c; return ;}
	pushdown(now);
	int mid = (l + r) / 2;
	if(rr <= mid) change(t[now].lc, l, mid, ll, rr, c);
	else if(ll > mid) change(t[now].rc, mid + 1, r, ll, rr, c);
	else change(t[now].lc, l, mid, ll, mid, c), change(t[now].rc, mid + 1, r, mid + 1, rr, c);
	update(now);
}

void cc(int x, int y, int c) {
	if(x < 0 || y < 0 || x >= n || y >= m || v[x * m + y]) return ;
	v[x * m + y] = 1;
	int m1 = n * m, m2 = n * m;
	for(int k = 0; k < 2; k++) {
		int nx = x + dx[k], ny = y + dy[k];
		if(nx < 0 || ny < 0);
		else {
			if(g[nx * m + ny] < m1) m2 = m1, m1 = g[nx * m + ny];
			else if(g[nx * m + ny] < m2) m2 = g[nx * m + ny];
		}
	} if(m1 > g[x * m + y]) change(1, 1, n * m, g[x * m + y] + 1, m1, c);
	for(int k = 2; k < 4; k++) {
		int nx = x + dx[k], ny = y + dy[k];
		if(nx >= n || ny >= m);
		else {
			if(g[nx * m + ny] < m1) m2 = m1, m1 = g[nx * m + ny];
			else if(g[nx * m + ny] < m2) m2 = g[nx * m + ny];
		}
	} if(m2 < g[x * m + y]) change(1, 1, n * m, m2 + 1, g[x * m + y], c);
}

void clear(int x, int y) {
	v[x * m + y] = 0;
	for(int k = 0; k < 4; k++) {
		int nx = x + dx[k], ny = y + dy[k];
		if(nx < 0 || ny < 0 || nx >= n || ny >= m) continue;
		v[nx * m + ny] = 0;
	}
}

void give_initial_chart(int h, int w, vector<int>_r, vector<int>_c) {
	n = h, m = w;
	for(int i = 0; i < n * m; i++) {
		R[i] = _r[i], C[i] = _c[i];
		g[R[i] * m + C[i]] = i;
	} bt(1, n * m);
	for(int i = 0; i < n; i++) for(int j = 0; j < m; j++) cc(i, j, 1);
	memset(v, 0, sizeof(v));
}

int swap_seats(int a, int b) {
	int ax = R[a], ay = C[a];
	int bx = R[b], by = C[b];
	clear(ax, ay), clear(bx, by);
	cc(ax, ay, -1), cc(bx, by, -1);
	for(int k = 0; k < 4; k++) cc(ax + dx[k], ay + dy[k], -1);
	for(int k = 0; k < 4; k++) cc(bx + dx[k], by + dy[k], -1);
	swap(g[ax * m + ay], g[bx * m + by]);
	swap(R[a], R[b]), swap(C[a], C[b]);
	clear(ax, ay), clear(bx, by);
	cc(ax, ay, 1), cc(bx, by, 1);
	for(int k = 0; k < 4; k++) cc(ax + dx[k], ay + dy[k], 1);
	for(int k = 0; k < 4; k++) cc(bx + dx[k], by + dy[k], 1);
	if(t[1].c == 1) return t[1].s;
	else return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值