ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

Educational Codeforces Round 122 E. Spanning Tree Queries

2022-02-04 13:03:34  阅读:170  来源: 互联网

标签:Educational int ed 询问 Tree Codeforces 最小 edge 权值


原题链接

题目大意

可以一张\(n\)个节点\(m\)条边的无向图,对你进行\(k\)次询问,每次询问给你一个值\(x\),让你求出权值\(\displaystyle\sum_{i=1}^{n-1}|w_i-x|\)最小的最小生成树,输出所有询问结果的异或和

题目分析

求最小生成树,我们首先会想到Kruskal算法来求解,但是询问次数特别多,所以每次询问用Kruskal求最小生成树肯定会超时

考虑一下Kruskal算法的过程,如果每次询问的值\(x\)比原来增加1,但是权值的大小顺序没有发生改变,那么最小生成树边的选择一定不会改变,接下来我们只需要思考一下,\(x\)什么时候会改变权值的大小顺序

假设有边\(i,j\)权值为\(w_i,w_j\),当\(x\le \frac{w_i+w_j}{2}\)的时候,\(|x-w_i|\)和\(|x-w_j|\)的大小顺序不发生改变;而当\(x\ge \frac{w_i+w_j}{2}+1\)的时候,权值的大小顺序发生改变,那么最小生成树就有重新选边的必要了。所以我们可以将\(\frac{w_i+w_j}{2}+1\)作为分界点,让其对应一个最小生成树的选边情况。

这样一来,我们先求出这张图中任意两条边的分界点,看作是最小生成树的一种情况,并将该情况的所有边权存储下来,时间复杂度为\(O(m^2)\),数据量最坏为\(90000\)。通过二分来确定询问所在的区间,通过存下来的边权的情况,求出询问的结果,最后得到答案

代码

#include <bits/stdc++.h>
using namespace std;

#define _range(container) container.begin(), container.end()
#define L_B lower_bound
#define U_B upper_bound

constexpr int N = 1e5 + 100;
int n, m;
int cur[N], p[N], cnt;
LL result[N], res;
VI ed, order[N];

struct Edge {
  int a, b, w;
} edge[N];

int _x;
inline bool cmp(Edge a, Edge b) {
  return abs(_x-a.w) < abs(_x-b.w);
}

int find(int x) {
  if (x != p[x]) p[x] = find(p[x]);
  return p[x];
}

int main() {
  scanf("%d%d", &n, &m);

  for (int i = 0; i < m; i++) {
    int a, b, c;
    scanf("%d%d%d", &a, &b, &c);
    edge[i] = {a, b, c};
  }

  for (int i = 1; i < m; i++)
    for (int j = 0; j < i; j++) {
      int mid = (edge[i].w + edge[j].w) / 2 + 1;
      ed.emplace_back(mid);
    }
  
  // 特殊情况,当询问的x=0,那么问题就变成求最小生成树
  ed.emplace_back(0);
  sort(_range(ed));

  int cnt = 0;
  for (auto x : ed) {
    _x = x;
    sort(edge, edge + m, cmp);
    for (int i = 0; i <= n + 1; i++) p[i] = i;

    for (int i = 0; i < m; i++) {
      int a = find(edge[i].a), b = find(edge[i].b), w = edge[i].w;
      if (a != b) {
        p[a] = b;
        order[cnt].emplace_back(w);
      }
    }
    cnt++;
  }

  int p, k, a, b, c, x;
  scanf("%d%d%d%d%d", &p, &k, &a, &b, &c);

  for (int i = 1; i <= k; i++) {
    if (i <= p) scanf("%d", &x);
    else x = (x * 1LL * a + b) % c;
   
    int t = U_B(_range(ed), x) - ed.begin() - 1;
    LL sum = 0;
    for (auto e : order[t]) 
      sum += abs(e - x);
    res ^= sum;
  }

  printf("%lld\n", res);

  return 0;
}

标签:Educational,int,ed,询问,Tree,Codeforces,最小,edge,权值
来源: https://www.cnblogs.com/FrankOu/p/15862680.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有