额这篇和上一篇当初不知道为什么没有放到博客园上,现在才想起来,见谅。
question
有 \(N\) 只鸽子,编号从 \(1\) 到 \(N\),有 \(N\) 个鸽巢,编号从 \(1\) 到 \(N\)。最初,鸽子 \(i\) 在巢 \(i(1\leq i\leq N)\) 中。
您会收到 \(Q\) 个查询,您必须按顺序处理这些查询。查询有两种类型,每种都以下列格式之一给出:
1 P H
:将鸽子 \(P\) 移到鸽巢 \(H\) 中。2
:输出包含一只以上鸽子的鸽巢数量。
solution
首先我们解决操作 \(1\)。
我们让 \(a_i\) 表示巢 \(i\) 的鸽子数量,同时让 \(b_i\) 表示鸽子 \(i\) 目前所处的巢相对于初始的巢 \(i\) 偏移了多少。
那么我们可以得到以下代码。
if (opt == 1){int p, h;cin >> p >> h;int now = p + b[p];// 鸽子 p 目前所处的巢的编号为 nowa[now]--;a[h]++;b[p] = h - p;// 更新b[i]
}
接下来我们考虑操作 \(2\)。
显然不能每次的扫一遍 \(a\) 数组,所以我们在操作 \(1\) 中加一步。对于每次操作 \(1\),有可能对答案做出贡献的只有 \(a_{now}\) 和 \(a_h\),所以我们进行分类讨论。
-
若 \(a_{now}\) 操作完后等于 \(1\),则说明 \(a_{now}\) 操作之前一定符合条件,那么我们让答案减 \(1\)。
-
若 \(a_h\) 操作完后大于 \(1\),且 \(a_h\) 操作之前不符条件,那么我们让答案加 \(1\)。
为了方便,我们记录 \(f_i\) 表示巢 \(i\) 当前是否符合条件。整体思路出来了,以下是完整代码。
#include <bits/stdc++.h>
using namespace std;#define int long longconst int N = 1e8 + 5;int n, q;
int a[N], b[N];
int cnt;
bool f[N];signed main(){cin.tie(0)->sync_with_stdio(0);cin >> n >> q;for (int i = 1; i <= n; i++)// 给 a 数组付赋初值a[i] = 1;while (q--){int opt;cin >> opt;if (opt == 1){int p, h;cin >> p >> h;int now = p + b[p];a[now]--;a[h]++;b[p] = h - p;if (a[now] == 1) cnt--, f[now] = 0;if (a[h] > 1 && !f[h]) cnt++, f[h] = 1;}else if (opt == 2)cout << cnt << "\n";}return 0;
}