Deltix Round, Autumn 2021 (open for everyone, rated, Div. 1 + Div. 2)

118 阅读2分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 10 月更文挑战」的第21天,点击查看活动详情
本文已参与「新人创作礼」活动,一 起开启掘金创作之路。

题目

image.png

中文翻译

威廉来到了一个专门讨论加密货币的会议。要想了解加密货币世界的最新消息,建立联系、认识新朋友、利用朋友的关系是必不可少的。 会议有N个参与者,他们最初都不熟悉对方。威廉可以把之前不熟悉的任何两个人a和b介绍给对方。 威廉有d个条件,其中第i个条件要求人xi与人yi有联系。从形式上看,如果有这样一条链p1=x,p2,p3,...,pk=y,对于1到k-1的所有i来说,编号为pi和pi+1的两个人确实认识对方,则两个人有联系。 对于每一个i(1≤i≤d),威廉希望你能计算出一个人能够拥有的最大的熟人数量,假设威廉满足从1到i(包括i)的所有条件,并且正好进行了i次介绍。这些条件是在威廉进行了i次介绍之后被检查的。每个i的答案必须独立计算。这意味着,当你计算i的答案时,你应该假设还没有两个人被介绍给对方。

题意

n个人有d个关系我们依次输入两人之前的关系在我们输入这次关系之前要确保之前的关系是都成立的,每次我们都有一次机会可以随机让两个人之间有关系但是我们要确保我们输入的关系也是要成立的

解法

如果两人之间有关系那么我们就可以认为他们在同一个关系块中因为这样我们就可以去使用并查集去维护这个关系在我们每次输入一个关系的时候我们可以先判断我们输入的这个关系是否是成立的如果是成立的那么我们就可以多选择一个块去连接

int a[N];
int find(int x) {return f[x] == x ? f[x] : f[x] = find(f[x]);}//并查集
void solve()
{
   int cnt = 0;
   int n,d; cin >> n >> d;
   rep(i,n) f[i] = i,a[i] = 1;//初始化每个关系快中肯定有一个
   rep(i,d) {
      int x,y; cin >> x >> y;
      set<int> st;//set去维护这个块是否被使用过
      priority_queue<int> q;//让几个最大的块联通
      int fa = find(x),fb = find(y);
      if(fa != fb) {
         a[fa] += a[fb];
         f[fb] = fa;
      }else cnt ++;
      for(int j = 1; j <= n; j++) {
         if(!st.count(find(j))) {
            st.insert(find(j));
            q.push(a[find(j)]);
            // cout << a[find(j)] << ' ';
         }
      }
      int res = 0;
      int k = cnt + 1;
      while(k --) {
         res += q.top();
         q.pop();
      }
      cout << res - 1 << endl;
   }
}