问题描述

We have a graph with N vertices, numbered 0 through N−1. Edges are yet to be added.

We will process Q queries to add edges. In the i-th (1≦iQ) query, three integers A**i,B**i and C**i will be given, and we will add infinitely many edges to the graph as follows:

  • The two vertices numbered A**i and B**i will be connected by an edge with a weight of C**i.
  • The two vertices numbered B**i and A**i+1 will be connected by an edge with a weight of C**i+1.
  • The two vertices numbered A**i+1 and B**i+1 will be connected by an edge with a weight of C**i+2.
  • The two vertices numbered B**i+1 and A**i+2 will be connected by an edge with a weight of C**i+3.
  • The two vertices numbered A**i+2 and B**i+2 will be connected by an edge with a weight of C**i+4.
  • The two vertices numbered B**i+2 and A**i+3 will be connected by an edge with a weight of C**i+5.
  • The two vertices numbered A**i+3 and B**i+3 will be connected by an edge with a weight of C**i+6.
  • ...

Here, consider the indices of the vertices modulo N. For example, the vertice numbered N is the one numbered 0, and the vertice numbered 2N−1 is the one numbered N−1.

输入格式

The input is given from Standard Input in the following format:

N Q

A1 B1 C1

A2 B2 C2

:

AQ BQ CQ

输出格式

Print the total weight of the edges contained in a minimum spanning tree of the graph.

样例输入

7 1

5 2 1

样例输出

21

解析

考虑等价替换。对于一次加边操作,由于 (x,y) 的权值比 (y,x+1) 的权值小,考虑kruskal 的过程,在考虑边 (y,x+1,z+1) 的时候,x,y 一定已在一个连通块里。于是,我们可以将 (y,x+1,z+1) 等价替换为 (x,x+1,z+1)。同理,(x+1,y+1,z+2) 可替换为(y,y+1,z+2)。经过这样的替换后,我们发现,一次加边操作会使图上产生两个环,以a为起点的环的路径为c+1,c+3,c+5,......,以b为起点的环的路径为c+2,c+4,c+6,......,同时还有(a,b,c)的边。设\(f[i]\)表示从i-1到i之间的边中最小的,我们可以用类似于最大前缀的方式,求出每一个f:

\[f[i+1]=max(f[i+1],f[i])
\]

注意\(f[n+1]=f[1]\),因为在更新一圈后可能还有可以被后来的点更新的,所以我们要更新两圈。

最后,图中只剩下q+n条边,用Kruskal求最大生成树即可。

代码

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
#define int long long
#define N 400002
using namespace std;
struct edge{
int u,v,w;
}e[N];
int n,q,i,f[N],num,fa[N];
int read()
{
char c=getchar();
int w=0;
while(c<'0'||c>'9') c=getchar();
while(c<='9'&&c>='0'){
w=w*10+c-'0';
c=getchar();
}
return w;
}
int my_comp(const edge &x,const edge &y)
{
return x.w<y.w;
}
int find(int x)
{
if(x!=fa[x]) fa[x]=find(fa[x]);
return fa[x];
}
int Kruscal()
{
for(int i=1;i<=n;i++) fa[i]=i;
sort(e+1,e+num+1,my_comp);
int cnt=n,ans=0;
for(int i=1;i<=num;i++){
int f1=find(e[i].u),f2=find(e[i].v);
if(f1!=f2){
fa[f1]=f2;
cnt--;
ans+=e[i].w;
}
}
return ans;
}
signed main()
{
memset(f,0x3f,sizeof(f));
n=read();q=read();
for(i=1;i<=q;i++){
int a,b,c;
a=read()+1;b=read()+1;c=read();
e[++num]=(edge){a,b,c};
f[a]=min(f[a],c+1);
f[b]=min(f[b],c+2);
}
bool flag=0;
for(i=1;i<=n;i++){
f[i%n+1]=min(f[i]+2,f[i%n+1]);
if(i==n&&!flag) i=0,flag=1;
}
for(i=1;i<=n;i++) e[++num]=(edge){i,i%n+1,f[i]};
cout<<Kruscal()<<endl;
return 0;
}

最新文章

  1. mas_makeConstraints &amp;&amp; mas_remakeConstraints &amp;&amp; mas_updateConstraints 用法与注意事项
  2. 雅虎(yahoo)前端优化十四条军规
  3. ObjectOutputStream序列化问题
  4. [I2C]I2C总线协议图解
  5. PL/SQL如何导入dmp文件
  6. 搭建maven环境
  7. How to read the HTML DTD
  8. MySQL连接问题浅析
  9. Xcode Provisioning 路径
  10. OpenJudge 2815 城堡问题 / Poj 1164 The Castle
  11. Authorization user to use specifical database
  12. 文件服务器的详细配置之共享权限与NTFS权限的设置
  13. linux (ubuntu) 命令学习笔记
  14. Salesforce的公式和验证规则
  15. 不一样的go语言-gopher
  16. (4.21)sql server中复制查询结果集
  17. 11、可扩展MySQL+12、高可用
  18. mysql查询字段时实现左右补零
  19. Ossec添加Agent端流程总结
  20. [原]设置vs的release版本调试

热门文章

  1. Splinter 的认识和基础应用
  2. SQL优化—nested loop优化
  3. 【洛谷P5018 对称二叉树】
  4. ConcurrentLinkedQueue 源码分析
  5. AtomicInteger 源码分析
  6. 术语-EDI:EDI
  7. 一个包含n个结点的四叉树,每一个节点都有4个指向孩子节点的指针,这4n个指针有(3*n+1)个空指针. 4*n-(n-1) = 3*n+1
  8. python抽象篇:面向对象基础
  9. 阶段1 语言基础+高级_1-3-Java语言高级_06-File类与IO流_01 File类_8_File类遍历(文件夹)目录功能
  10. 20190925 On Java8 第二十二章 枚举