P9571 题解

题目传送门

思路

先发个和题解区其它题解不一样的思路。

这题我们可以定义一个变量 sumsum,代表当前的直线数量。再定义一个 map 变量 tottot,其中 totitot_i 表示题目中的 kkii 的直线数量。最后定义一个 map 套 map 变量 mpmp(当然你也可以用 map <pair <int, int>, int> 的形式),其中 mpi,jmp_{i,j} 表示 kkiibbjj 的直线数量。

我们设 opop 是问题类型,当 op=1op=1 时,我们只要对 sum,totk,mpk,bsum,tot_k,mp_{k,b} 分别加上 11 即可。

op=2op=2 时,题目要求恰好有一个公共点。而要使一条直线恰好与要求的直线只有一个公共点,则要使两条直线是不平行的,即 kk 不相等,所以答案就成了 sumtotksum-tot_k

op=3op=3 时,题目要求至少有一个公共点。而要使一条直线至少与要求的直线一个公共点,则要使两条直线是不平行的,或是两条线完全重合,即 kk 不相等,或是 kkbb 都相等,所以我们在更改的时候可以先设一个临时的 map 变量 temptemp,用于存储 mpkmp_k,因为只有 mpkmp_k 才可能被保留。而直线总数 sumsum 变成了 totkmpk,btot_k-mp_{k,b}。接着,我们把 mpmptottot 都清空了,把 totktot_k 赋为 sumsum,因为只有 kk 相同的才能保留下来。现在,我们把刚才存下来的 temptemp 赋值到 mpkmp_k 里,并把 mpk,bmp_{k,b} 赋为 00

但是,提交后你会发现 TLE 在最后一个点了,为什么?因为清空太慢了,要知道,clear 函数可以 O(n)O(n) 的!所以我们就干脆不清空了,开 10510^5 个 map 套 map,反正只要没用过它就不会占空间。

但是你还是在最后一个点 MLE 了。看来占用的空间还是太多了,说明用的轮数(即 op=3op=3 的次数)太多了,这时候我们考虑不要 clear 了,直接将 mpimp_impi+1mp_{i+1} 交换即可。这样,就 AC 了。

代码

# include <bits/stdc++.h>
using namespace std;
int n, op, k, b, sum, maxx, now;
map <int, int> tot[100005];
map <int, map <int, int>> mp[100005];
int main () {
	cin >> n;
	while (n --) {
		cin >> op >> k >> b;
		if (op < 2)
			++ tot[now][k], ++ sum, ++ mp[now][k][b];
		else if (op < 3)
			cout << sum - tot[now][k] << '\n';
		else
			++ now, swap (mp[now][k], mp[now - 1][k]), tot[now][k] = sum = tot[now - 1][k] - mp[now][k][b], mp[now][k][b] = 0;
	}
	return 0;
}
posted @ 2023-08-20 00:07  Vitamin_B  阅读(19)  评论(0)    收藏  举报  来源