首页 > 其他分享 >G - Mediator

G - Mediator

时间:2024-05-06 21:12:39浏览次数:22  
标签:Mediator vertex vertices st mp query mod

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

相关文章

  • AtCoder Beginner Contest 350 G - Mediator
    链接:https://atcoder.jp/contests/abc350/tasks/abc350_g大致题意:给出n个点,q个询问1号询问要求u,v之前加一条无向边图始终是一个森林2号询问询问是否有一个点与u,v都相邻,若有则输出该点,若无则输出0。询问强制在线。思路:在题目要求的图中,满足2号询问的点只有三种情况:要么这个......
  • 【中介者模式(Mediator)】使用Java实现中介者模式
    引言中介者,何为中介者,顾名思义就是我们的在处理A和B之间的关系的时候,引入一个中间人,来处理这两者之间的关系,例如生活中我们需要去租房,买房,都会有中介,来处理房东和租客之间的协调关系,这个就是中介者,落实到具体的代码中呢,就像我们的Controller可能会依赖很多的Service层面......
  • typescript: Mediator pattern
     /****Mediatorpattern中介者是一种行为设计模式,让程序组件通过特殊的中介者对象进行间接沟通,达到减少组件之间依赖关系的目的。*file:Mediatorts.ts*TheMediatorinterfacedeclaresamethodusedbycomponentstonotifythe*mediatoraboutvarious......
  • Mediator Pattern
    MediatorPattern就类似现实生活中的中介(中间人),房屋中介、媒婆中介、权利寻租中介...,现实中为什么需要中介,在现实中的原因主要是两个一为了保护双方当事人的安全,只要中介人不泄密,他们双方就可以秘密的把交易完成,并且双方都是安全的。二是买卖双方并不信任双方,但是他们都共同的......
  • CSharp: Mediator Pattern in donet core 6
     ///<summary>///中介者模式MediatorPattern亦称:调解人、控制器、Intermediary、Controller、Mediator///</summary>publicabstractclassUser......
  • 中介者模式(Mediator )
    用来降低多个对象和类之间的通信复杂性。这种模式提供了一个中介类,该类通常处理不同类之间的通信,并支持松耦合,使代码易于维护。场景:公司多个部门之间,若直接互相打交......
  • Python: Mediator Pattern
    DuMediator.py#中介者模式MediatorPattern#ParticipantReference:importsys'''classUser(object):def__init__(self,med,name):self.media......
  • CSharp: Mediator Pattern
     ///<summary>///SummarydescriptionforRectangle.///MediatorPattern中介者模式///20220918///geovindu,GeovinDu,涂聚文///<......