G - Mediator
Problem Statement
Beware the special input format and the smaller memory limit than usual.
There is an undirected graph with vertices $1, 2, \dots, N$, initially without edges.
You need to process the following $Q$ queries on this graph:
1 u v
Type $1$: Add an edge between vertices $u$ and $v$.
Before adding the edge, $u$ and $v$ belong to different connected components (i.e., the graph always remains a forest).
2 u v
Type $2$: If there is a vertex adjacent to both $u$ and $v$, report its vertex number; otherwise, report $0$.
Given that the graph always remains a forest, the answer to this query is uniquely determined.
The queries are given in an encrypted form.
The original query is defined by three integers $A, B, C$, and the encrypted query is given as three integers $a, b, c$.
Let $X_k$ be the answer to the $k$-th type-$2$ query. Define $X_k = 0$ for $k = 0$.
Restore $A, B, C$ from the given $a, b, c$ as follows:
- Let $l$ be the number of type-$2$ queries given before this query (not counting the query itself). Then, use the following:
- $A = 1 + (((a \times (1+X_l)) \mod 998244353) \mod 2)$
- $B = 1 + (((b \times (1+X_l)) \mod 998244353) \mod N)$
- $C = 1 + (((c \times (1+X_l)) \mod 998244353) \mod N)$
Constraints
- All input values are integers.
- $2 \le N \le 10^5$
- $1 \le Q \le 10^5$
- $1 \le u < v \le N$
- $0 \le a,b,c < 998244353$
Input
The input is given from Standard Input in the following format:
$N$ $Q$
$\rm{Query}$$_1$
$\rm{Query}$$_2$
$\vdots$
$\rm{Query}$$_Q$
Output
Let $k$ be the number of type-$2$ queries. Print $k$ lines.
The $i$-th line should contain the answer to the $i$-th type-$2$ query.
Sample Input 1
6 12
143209915 123840720 97293110
89822758 207184717 689046893
67757230 270920641 26993265
952858464 221010240 871605818
730183361 147726243 445163345
963432357 295317852 195433903
120904472 106195318 615645575
817920568 27584394 770578609
38727673 250957656 506822697
139174867 566158852 412971999
205467538 606353836 855642999
159292205 319166257 51234344
Sample Output 1
0
2
0
2
6
0
1
After decrypting all queries, the input is as follows:
6 12
2 1 3
1 2 6
1 2 4
1 1 3
2 4 6
2 1 4
1 5 6
1 1 2
2 1 4
2 2 5
2 3 4
2 2 3
This input has a $6$-vertex graph and $12$ queries.
- The first query is
2 1 3
.- No vertex is adjacent to both vertex $1$ and vertex $3$, so report $0$.
- The second query is
1 2 6
.- Add an edge between vertices $2$ and $6$.
- The third query is
1 2 4
.- Add an edge between vertices $2$ and $4$.
- The fourth query is
1 1 3
.- Add an edge between vertices $1$ and $3$.
- The fifth query is
2 4 6
.- The vertex adjacent to both vertices $4$ and $6$ is vertex $2$.
- The sixth query is
2 1 4
.- No vertex is adjacent to both vertices $1$ and $4$, so report $0$.
- The seventh query is
1 5 6
.- Add an edge between vertices $5$ and $6$.
- The eighth query is
1 1 2
.- Add an edge between vertices $1$ and $2$.
- The ninth query is
2 1 4
.- The vertex adjacent to both vertices $1$ and $4$ is vertex $2$.
- The tenth query is
2 2 5
.- The vertex adjacent to both vertices $2$ and $5$ is vertex $6$.
- The eleventh query is
2 3 4
.- No vertex is adjacent to both vertices $3$ and $4$, so report $0$.
- The twelfth query is
2 2 3
.- The vertex adjacent to both vertices $2$ and $3$ is vertex $1$.
Sample Input 2
2 1
377373366 41280240 33617925
Sample Output 2
The output may be empty.
解题思路
容易想到的暴力思路是,给每个节点开一个 std::set
存储邻点。对于询问 $(u,v)$,枚举 $u$ 的每个邻点 $x$ 并判断 $x$ 是否为 $v$ 的邻点。一次询问的时间复杂度为 $O(n \log{n})$。
$q$ 个询问肯定会超时。我们本质是想知道 $u$ 与 $v$ 的邻点是否有交集,为此可以给每个节点开一个 std::bitset
标记其邻点(如果与节点 $x$ 相邻则第 $x$ 位置为 $1$)。对于询问 $(u,v)$ 则只需将对应的两个 std::bitset
按位与然后找到为 $1$ 的位置(或报告没有)。一次询问的时间复杂度为 $O\left(\frac{n}{w}\right)$,在 $3s$ 的时限内是可以通过的,但空间复杂度是 $O\left(n^2\right)$,显然会爆掉。
当我们想到两种暴力做法时可以尝试根号分治了,由于是图论的问题,一般根据节点的轻重来分类,参考交友问题。设置一个阈值 $b$,当节点的度数超过 $b$ 时(也就是重点),就给这个节点开一个 std::bitset
。容易知道重点的数量大致是 $O\left(\frac{n}{b}\right)$ 级别的,因此 std::bitset
的空间复杂度就是 $O\left(\frac{n^2}{b}\right)$。
由于是强制在线,所以在加边的过程中需要动态维护节点的度数,当加完变后节点的度数超过 $b$,就需要为该节点开一个 std::bitset
,然后枚举 std::set
中的节点进行标记。在所有的询问中,总计算量是 $O\left(b \cdot \frac{n}{b}\right)$。
对于询问 $(u,v)$,不失一般性假设 $u$ 比 $v$ 的度数小(否则可以交换 $u$ 和 $v$ 而不影响结果)。如果 $u$ 的度数不超过 $b$,则执行第一种暴力,时间复杂度为 $O(b \log{n})$。否则 $u$ 和 $v$ 的度数都超过 $b$,则执行第二种暴力,时间复杂度为 $O\left(\frac{n}{w}\right)$。
可以取 $b = \sqrt{n}$ 或 $b = \frac{n}{w \cdot log{n}}$,都可以过,下面代码取 $b = \sqrt{n}$(会更快些)。
AC 代码如下,时间复杂度为 $O\left(q \sqrt{n} \log{n} + q \frac{n}{w}\right)$:
#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
const int N = 1e5 + 5, B = 320, mod = 998244353;
set<int> st[N];
int main() {
int n, m;
scanf("%d %d", &n, &m);
int t = 0;
map<int, bitset<N>> mp;
while (m--) {
int a, b, c;
scanf("%d %d %d", &a, &b, &c);
a = 1 + (a * (1ll + t) % mod) % 2;
b = 1 + (b * (1ll + t) % mod) % n;
c = 1 + (c * (1ll + t) % mod) % n;
if (a == 1) {
st[b].insert(c);
if (st[b].size() > B) {
if (!mp.count(b)) {
for (auto &x : st[b]) {
mp[b][x] = 1;
}
}
mp[b][c] = 1;
}
st[c].insert(b);
if (st[c].size() > B) {
if (!mp.count(c)) {
for (auto &x : st[c]) {
mp[c][x] = 1;
}
}
mp[c][b] = 1;
}
}
else {
if (st[b].size() > st[c].size()) swap(b, c);
if (st[b].size() <= B) {
t = 0;
for (auto &x : st[b]) {
if (st[x].count(c)) {
t = x;
break;
}
}
}
else {
bitset<N> bs = mp[b] & mp[c];
if (bs.any()) t = bs._Find_first();
else t = 0;
}
printf("%d\n", t);
}
}
return 0;
}
参考资料
AtCoder Beginner Contest 350:https://www.cnblogs.com/No-play-Yes-splay/p/18148245/atcoder-beginner-contest-350-sol
AtCoder Beginner Contest 350 A 至 G 題讲解 by dreamoon:https://www.bilibili.com/video/BV1Ub421Y7GZ/
标签:Mediator,vertex,vertices,st,mp,query,mod From: https://www.cnblogs.com/onlyblues/p/18175932