首页 > 其他分享 >【题解】P4898 [IOI2018] seats 排座位

【题解】P4898 [IOI2018] seats 排座位

时间:2023-04-07 22:00:53浏览次数:35  
标签:tmp IOI2018 return int 题解 P4898 ch inf ql

思路

线段树。

题意可以转化成每次判定有多少个前缀满足所有结点构成矩形。

首先排除确定矩阵坐标再数答案的做法,因为太难。

所以考虑如何对前缀进行判定。

一个简单的想法是维护前 \(i\) 个点中 \(x, y\) 坐标的最值,但这样只能暴力看矩阵中的所有元素,跑得很慢。

不妨思考一下合法的条件:

  • 前 \(i\) 个点都可以被一个矩形覆盖,这个恒成立。

  • 这个矩形内没有其他的点。

对于 2,考虑把前 \(i\) 个点和剩下的点分开,考虑把前 \(i\) 个染成黑色,后面的染成白色。

于是现在可以考虑黑白分布情况:

  • 所有的黑点必须连通,等价于左边的相邻点和上边的相邻点都是白点的黑点只有 \(1\) 个。

  • 矩形内没有白点,也就是说黑点不会有 L 形的分布,等价于不存在相邻点中有超过一个黑点的白点。

结论不会证,但是是对的,差点猜出来。

不太好维护每个时刻图内的状况。

换个角度,既然每次交换至多影响 \(10\) 个点的状态,那直接维护每个点对答案的贡献,每次只需要 \(O(\log)\) 计算贡献就能做。

先考虑第一个条件。如果点 \((x, y)\) 在时刻 \(i\) 是合法的,那么显然有 \(t_{x, y} \leq i < \min(t_{x - 1, y}, t_{x, y - 1})\).

第二个条件同理有 \(\operatorname{SecondMin(t_{x - 1, y}, t_{x, y - 1}, t_{x + 1, y}, t_{x, y + 1})} \leq i < t_{x, y}\).

于是一个点可以贡献的时刻都是确定的,直接对于点动态算贡献就好了。

注意四连通的点处理出来之后要去重,不然就会喜提 56pts.

代码

#include <cstdio>
#include <vector>
#include <algorithm>
using namespace std;

typedef pair<int, int> pii;
#define il inline
#define fi first
#define se second
#define mp make_pair

const int maxn = 1e6 + 5;
const int sgt_sz = maxn << 2;
const int inf = 2e9;

int h, w, q, n;
int tmp[4];
int r[maxn], c[maxn];
int dx[5] = {0, -1, 1, 0, 0}, dy[5] = {0, 0, 0, -1, 1};
pii que[10];
vector<int> a[maxn];

il int read()
{
	int res = 0;
	char ch = getchar();
	while ((ch < '0') || (ch > '9')) ch = getchar();
	while ((ch >= '0') && (ch <= '9')) res = res * 10 + ch - '0', ch = getchar();
	return res;
}

il void write(int x)
{
	if (x > 9) write(x / 10);
	putchar(x % 10 + '0');
}

il void write(int x, char ch) { write(x), putchar(ch); }

namespace SGT
{
	#define ls (k << 1)
	#define rs (k << 1 | 1)

	int lazy[sgt_sz];

	struct node
	{
		int v[2], c[2];

		node() { v[0] = v[1] = c[0] = c[1] = 0; }

		friend node operator + (node a, node b)
		{
			node res;
			res.v[0] = min(a.v[0], b.v[0]);
			res.v[1] = min(max(a.v[0], b.v[0]), min(a.v[1], b.v[1]));
			if (res.v[0] == res.v[1]) res.v[1] = inf;
			for (int i = 0; i < 2; i++)
				for (int j = 0; j < 2; j++)
				{
					if (res.v[i] == a.v[j]) res.c[i] += a.c[j];
					if (res.v[i] == b.v[j]) res.c[i] += b.c[j];
				}
			return res;
		}
	} tr[sgt_sz];

	il void push_up(int k) { tr[k] = tr[ls] + tr[rs]; }

	il void push_down(int k)
	{
		tr[ls].v[0] += lazy[k], tr[ls].v[1] += lazy[k], lazy[ls] += lazy[k];
		tr[rs].v[0] += lazy[k], tr[rs].v[1] += lazy[k], lazy[rs] += lazy[k];
		lazy[k] = 0;
	}

	il void build(int k, int l, int r)
	{
		lazy[k] = 0, tr[k].v[1] = inf, tr[k].c[0] = r - l + 1;
		if (l == r) return;
		int mid = (l + r) >> 1;
		build(ls, l, mid), build(rs, mid + 1, r);
	}

	il void update(int k, int l, int r, int ql, int qr, int w)
	{
		if (ql > qr) return;
		if ((l >= ql) && (r <= qr)) return tr[k].v[0] += w, tr[k].v[1] += w, lazy[k] += w, void();
		push_down(k);
		int mid = (l + r) >> 1;
		if (ql <= mid) update(ls, l, mid, ql, qr, w);
		if (qr > mid) update(rs, mid + 1, r, ql, qr, w);
		push_up(k);
	}

	il int query()
	{
		if (tr[1].v[0] == 1) return tr[1].c[0];
		if (tr[1].v[1] == 1) return tr[1].c[1];
		return 0;
	}
}
using namespace SGT;

bool in(int x, int y) { return (x >= 1) && (x <= h) && (y >= 1) && (y <= w); }

int chk1(int x, int y)
{
	int res = n + 1;
	res = min(res, (x > 1 ? a[x - 1][y] : inf));
	res = min(res, (y > 1 ? a[x][y - 1] : inf));
	return res - 1;
}

int chk2(int x, int y)
{
	tmp[0] = (x > 1 ? a[x - 1][y] : inf), tmp[1] = (x < h ? a[x + 1][y] : inf);
	tmp[2] = (y > 1 ? a[x][y - 1] : inf), tmp[3] = (y < w ? a[x][y + 1] : inf);
	sort(tmp, tmp + 4);
	return tmp[1];
}

int main()
{
	h = read(), w = read(), q = read(), n = h * w;
	for (int i = 1; i <= h; i++) a[i].resize(w + 1);
	for (int i = 1; i <= n; i++)
	{
		r[i] = read() + 1, c[i] = read() + 1;
		a[r[i]][c[i]] = i;
	}
	build(1, 1, n);
	for (int i = 1; i <= h; i++)
		for (int j = 1; j <= w; j++)
			update(1, 1, n, a[i][j], chk1(i, j), 1), update(1, 1, n, chk2(i, j), a[i][j] - 1, 1);
	while (q--)
	{
		int u = read() + 1, v = read() + 1, len = 0;
		for (int i = 0, x, y, tx, ty; i < 5; i++)
		{
			x = r[u], y = c[u], tx = x + dx[i], ty = y + dy[i];
			if (in(tx, ty)) que[++len] = mp(tx, ty);
			x = r[v], y = c[v], tx = x + dx[i], ty = y + dy[i];
			if (in(tx, ty)) que[++len] = mp(tx, ty);
		}
		sort(que + 1, que + len + 1);
		len = unique(que + 1, que + len + 1) - que - 1;
		for (int i = 1, tx, ty; i <= len; i++)
		{
			tx = que[i].fi, ty = que[i].se;
			update(1, 1, n, a[tx][ty], chk1(tx, ty), -1), update(1, 1, n, chk2(tx, ty), a[tx][ty] - 1, -1);
		}
		swap(r[u], r[v]), swap(c[u], c[v]), swap(a[r[u]][c[u]], a[r[v]][c[v]]);
		for (int i = 1, tx, ty; i <= len; i++)
		{
			tx = que[i].fi, ty = que[i].se;
			update(1, 1, n, a[tx][ty], chk1(tx, ty), 1), update(1, 1, n, chk2(tx, ty), a[tx][ty] - 1, 1);
		}
		write(query(), '\n');
	}
	return 0;
}

标签:tmp,IOI2018,return,int,题解,P4898,ch,inf,ql
From: https://www.cnblogs.com/lingspace/p/p4898.html

相关文章

  • 【题解】CF472G Design Tutorial: Increase the Constraints
    《正解分块+FFT跑1min,__builtin_popcount暴力跑10s》《没人写正解,CF也不卡》思路正解:分块+FFT乱搞:__builtin_popcount首先我们知道哈明距离可以用一种\(O(|字符集||S|)\)的算法求。具体考虑枚举字符集中的每一个字符,将两个串中是该字符的位置看作\(1\),不是该字......
  • 【题解】臭气弹
    用次数乘上\(P/Q\)来构建增广矩阵,进行高斯消元。在算出每个点被摧毁的概率与所有点的期望出现次数。由于每个点爆炸概率相同,所以每个点被摧毁的概率就是这个点的期望出现次数\(/\)所有点的期望出现次数。#include<bits/stdc++.h>usingnamespacestd;constintN=311;......
  • 荣耀magicbook安装Linux系统boot fail问题解决
    偶然网上冲浪,发现了Debian系的kalilinux有点意思,刚好手边有一台不怎么用的荣耀magicbook,于是准备装个双系统好不容易下完了kali的镜像,使rufus写入了U盘但是在安装过程中怎么安装都显示bootfail,切换了n个版本的Linux系统,发现还是这样,但是实测Debian11是可以进入引导项的最后所......
  • CF1810E 题解
    一、题目描述:给你一个n个点,m条边的无向图,点带权,起点可任意选择。每走过一个新的点,你的能力值会+1。一开始你的能力值为0。你只能经过点权小于等于你能力值的点。每条边,每个点都可以经过无限次,问能否走遍整个图。如果可以,输出"YES"。否则输出"NO"。......
  • 洛谷P1552 [APIO2012] 派遣 题解 左偏树
    题目链接:https://www.luogu.com.cn/problem/P1552题目大意:每次求子树中薪水和不超过\(M\)的最大节点数。解题思路:使用左偏树维护一个大根堆。首先定义一个Node的结构体:structNode{ints[2],c,sz,dis;longlongsum;Node(){};Node(int_c){s......
  • 关于Qt在线安装报错的一些问题解决办法
    事情的起因是,换了一台新电脑,准备安装Qt,突发现安装不了,报错,一共有几种:1.   2.第二种是不能到选择安装的界面   3.第三种是可以选择了,也可以下载安装了,但是卡在一个地方不动了以上3种个人猜测可能是某些网络原因,至于是什么网络原因,大家自行脑补。不多说废话,经过我......
  • 【容斥、状压dp】主旋律 题解
    【清华集训2014】主旋律题解神秘题。题目简述给你一个有向图\(G=(V,E)\)。求有多少\(E\)的子集\(E'\)使得新图\(G'=(V,E')\)是强连通图。强连通图的定义是任意两点\(u,v\)均存在\(u\tov,v\tou\)的路径。\(n\leq15,m\leqn\times(n-1)\)。解题思路......
  • GMOI R2 T2 猫耳小(加强版) 官方题解
    首先特判\(k=0\)的情况,此时的答案为非\(0\)数的个数,改法是将它们全改成\(0\)。再特判\(k\)较大的情况,此时的答案为\(0\)。否则,对于\(k\)大小适中的情况,我们从前往后遍历数组,同时维护当前区间的\(\operatorname{mex}\)值。根据\(\operatorname{mex}\)的定义,显然对......
  • [HAOI2007]理想的正方形【题解】
    题目描述有一个\(a\timesb\)的整数组成的矩阵,现请你从中找出一个\(n\timesn\)的正方形区域,使得该区域所有数中的最大值和最小值的差最小。输入格式第一行为\(3\)个整数,分别表示\(a,b,n\)的值。第二行至第\(a+1\)行每行为\(b\)个非负整数,表示矩阵中相应位置上......
  • 奶牛排队【题解】
    题目描述奶牛在熊大妈的带领下排成了一条直队。显然,不同的奶牛身高不一定相同……现在,奶牛们想知道,如果找出一些连续的奶牛,要求最左边的奶牛\(A\)是最矮的,最右边的\(B\)是最高的,且\(B\)高于\(A\)奶牛。中间如果存在奶牛,则身高不能和\(A,B\)奶牛相同。问这样的奶牛最......