/*

最小树形图+保存路径

第一次想错了,各种wa,tle后网上看资料,找到一篇错误的题解。。。

最后用对着正解分析了一波,感觉对最小树形图又有了新的理解:最小树形图的精髓在于每张图更新的时间信息!

第一次感觉到如此神奇的算法,解释分散在注释里了

pass:交到cf上时加文件输入输出语句才能过

*/

/*
cf240e
最小树形图:输出路径板子
*/
#include<iostream>
#include<cstdio>
#include<cstring>
#define MAXN 100005
#define MAXM 2000005
#define ll long long
#define INF 0x7fffffff
using namespace std;
int pre[MAXN],vis[MAXN],in[MAXN],id[MAXN];
int usedEdge[MAXN],preEdge[MAXN];
struct Edge{
int u,v,w,ww,id;
Edge(){}
Edge(int uu,int vv,int _w,int _ww,int ii):u(uu),v(vv),w(_w),ww(_ww),id(ii){}
}edge[MAXM];
struct Used{
int pre,id;
}cancle[MAXM];//保留每次更新图时被取消的边id
int zhuliu(int root,int n,int m){
memset(usedEdge,,sizeof usedEdge);
int total=m,res=;
int u,v,w;
while(){
for(int i=;i<n;i++)in[i]=INF;
for(int i=;i<m;i++){
u=edge[i].u,v=edge[i].v,w=edge[i].w;
if(u!=v && w<in[v]){
in[v]=w;
pre[v]=u;
//记录这个顶点所在边的编号 !!!
preEdge[v]=edge[i].id;
}
}
for(int i=;i<n;i++)
if (i!=root && in[i]==INF) return -; int tn=;
memset(id,-,sizeof id);
memset(vis,-,sizeof vis);
in[root]=;
for(int i=;i<n;i++){
res+=in[i];
v=i;
//这条边被加入到当前图集合E中,这个点所在的边使用次数+1 !!!!
if(i!=root) usedEdge[preEdge[i]]++;
while(v!=root && id[v]==- && vis[v]!=i){
vis[v]=i;
v=pre[v];
}
if(id[v]==- && v!=root){
for(u=pre[v];u!=v;u=pre[u])
id[u]=tn;
id[v]=tn++;
}
}
if(tn==) break;
for(int i=;i<n;i++)
if(id[i]==-) id[i]=tn++; //准备更新旧图
for(int i=;i<m;i++){
u=edge[i].u,v=edge[i].v;
edge[i].u=id[u],edge[i].v=id[v];
if(id[u]!=id[v]){
edge[i].w-=in[v];
//将该边在旧图中的编号取消
cancle[total].id=edge[i].id;
cancle[total].pre=preEdge[v];
///将这条边id重新编号
edge[i].id=total++;
}
}
n=tn;
root=id[root];
}
//统计新建立(被重新编号)的边 !!!因为每重新编号一条边,就说明有一条边被取消一次,一因此需要将那条变得增加量也取消
//为什么要倒着往回遍历?因为必须沿着最终形成图的状态回溯逐步回溯到原图,找到边原始的id
//肯定是新建立的边导致了之前的边被取消掉,
for(int i=total-;i>=m;i--)
if(usedEdge[i]){//如果这条边被使用过(如果一条边仅仅是被重新编号而未被使用过,即只参与了边权值的改变但没有真正加入到某一次循环图中去,那么和其相关的边不用被取消)
usedEdge[cancle[i].id]++;//
usedEdge[cancle[i].pre]--;//把之前加的减掉
}
return res;
} int main(){
int n,m;
while(~scanf("%d%d",&n,&m)){
for(int i=;i<m;i++){
int u,v,w;
scanf("%d%d%d",&u,&v,&w);
u--;v--;
edge[i]=Edge(u,v,w,w,i);
}
int root=;
int ans=zhuliu(root,n,m);
if(ans==- || ans==)
printf("%d\n",ans);
else {
printf("%d\n",ans);
for(int i=;i<m;i++)
if(edge[i].ww== && usedEdge[i])
printf("%d ",i+);
printf("\n");
}
}
return ;
}

codeforce 240E的更多相关文章

  1. codeforce 240E 最小树形图+路径记录更新

    最小树形图的路径是在不断建立新图的过程中更新的,因此需要开一个结构体cancle记录那些被更新的边,保存可能会被取消的边和边在旧图中的id 在朱刘算法最后添加了一个从后往前遍历新建边的循环,这可以理解 ...

  2. Codeforce - Street Lamps

    Bahosain is walking in a street of N blocks. Each block is either empty or has one lamp. If there is ...

  3. Codeforce Round #216 Div2

    e,还是写一下这次的codeforce吧...庆祝这个月的开始,看自己有能,b到什么样! cf的第二题,脑抽的交了错两次后过了pretest然后system的挂了..脑子里还有自己要挂的感觉,果然回头 ...

  4. Codeforce 水题报告(2)

    又水了一发Codeforce ,这次继续发发题解顺便给自己PKUSC攒攒人品吧 CodeForces 438C:The Child and Polygon: 描述:给出一个多边形,求三角剖分的方案数( ...

  5. codeforce 375_2_b_c

    codeforce 375_2 标签: 水题 好久没有打代码,竟然一场比赛两次卡在边界条件上....跪 b.题意很简单...纯模拟就可以了,开始忘记了当字符串结束的时候也要更新两个值,所以就错了 #i ...

  6. codeforce 367dev2_c dp

    codeforce 367dev2_c dp 标签: dp 题意: 你可以通过反转任意字符串,使得所给的所有字符串排列顺序为字典序,每次反转都有一定的代价,问你最小的代价 题解:水水的dp...仔细想 ...

  7. 三维dp&codeforce 369_2_C

    三维dp&codeforce 369_2_C 标签: dp codeforce 369_2_C 题意: 一排树,初始的时候有的有颜色,有的没有颜色,现在给没有颜色的树染色,给出n课树,用m种燃 ...

  8. 强连通分量&hdu_1269&Codeforce 369D

    强连通分量 标签: 图论 算法介绍 还记得割点割边算法吗.回顾一下,tarjan算法,dfs过程中记录当前点的时间戳,并通过它的子节点的low值更新它的low,low值是这个点不通过它的父亲节点最远可 ...

  9. 【树状数组】区间出现偶数次数的异或和(区间不同数的异或和)@ codeforce 703 D

    [树状数组]区间出现偶数次数的异或和(区间不同数的异或和)@ codeforce 703 D PROBLEM 题目描述 初始给定n个卡片拍成一排,其中第i个卡片上的数为x[i]. 有q个询问,每次询问 ...

随机推荐

  1. 【tmos】spring boot项目中处理Schedule定时任务

    我的代码 /** * Author:Mr.X * Date:2017/10/30 14:54 * Description: */ @Component @Configurable @EnableSch ...

  2. PLSql的使用

    1.安装 plsqldeveloper和数据库驱动-ODAC 2.在数据库驱动ODAC中添加 Oracle客户端的网络服务名配置文件tnsnames.ora 路径为: 3.汉化 直接运行Languag ...

  3. Java HashMap、HashTable、TreeMap、WeakHashMap区别

    1.HashMap不是线程安全,而HashTable是线程安全

  4. Python 标准异常总结

    AssertionError 断言语句(assert) AttributeError 尝试访问未知的对象属性 EOFError 用户输入文件末尾标志EOF(Ctrl+d) FloatingPointE ...

  5. 【转】fnmatch模块的使用——主要作用是文件名称的匹配,并且匹配的模式使用的unix shell风格

    [转]fnmatch模块的使用 fnmatch模块的使用 此模块的主要作用是文件名称的匹配,并且匹配的模式使用的unix shell风格.fnmatch比较简单就4个方法分别是:fnmatch,fnm ...

  6. Alpha 冲刺 (3/10)

    目录 摘要 团队部分 个人部分 摘要 队名:小白吃 组长博客:hjj 作业博客:冲刺3 团队部分 后敬甲(组长) 过去两天完成了哪些任务 文字描述 组织第一次团队编程 继续阅读小程序开发文档 接下来的 ...

  7. vue中更换.ico图标报错路径找不到图片

    问题描述: vue项目中,想要更换.ico图片,更换完成后刷新页面报错,找不到路径. 解决: 更换完图片,重新启动下vue项目(npm run dev)就可以啦~ 哈哈哈 补充知识: 网页title旁 ...

  8. lua 中随机数产生

    需要用到两个函数: (1)math.randomseed(N):  接收一个整数N作为随机序列种子 (2)math.random([n, [m]]): 这个函数有三种用法,分别是不跟参数,此时产生(0 ...

  9. bootstrap4简单使用和入门03-响应式布局

    响应式布局的原理 页面源码 <!DOCTYPE html> <html lang="en"> <head> <meta charset=& ...

  10. jquery简单使用入门

    <!DOCTYPE html> <html> <head> <title>jquery</title> <meta charset=& ...