这是一个最小生成树,不过唯一的不同是这棵最小生成树是动态加边的,所以由此衍生了各种奇怪做法。
先说我的做法,我的做法很暴力,就是仅排序一遍,然后同时运行M个kruskal,总的时间复杂度应该是M^2,卡时间过了。
总之很裸很暴力。
然后Orz一下大神的做法:
1 插入排序+kruskal
2 逆序kruskal
3 神奇的找环弃max法
都好神Orz
上代码:
#include<iostream>
#include<cstdio>
#include<cstring>
#include<string>
#include<algorithm>
#include<cmath>
using namespace std;
int fa[6005][201];
int ans[6005];
int total[6005];
struct edge{
int to;
int f,dis;
int day;
};
edge e[10000+666];
int find(int day,int a)
{
if(fa[day][a]==a)return a;
else return fa[day][a]=find(day,fa[day][a]);
}
inline int ra()
{
int x=0;char ch=getchar();int flag=1;
while(ch>'9'||ch<'0'){if(ch=='-')flag=-1;ch=getchar();}
while(ch>='0'&&ch<='9'){x*=10;x+=ch-'0';ch=getchar();}
return x*flag;
}
bool cmp(const edge &x,const edge &y)
{
return x.dis<y.dis;
}
int cnt;
int n,m;
int main()
{
n=ra();m=ra();
for(int i=1;i<=m;i++)
{
e[i].f=ra();e[i].to=ra();
e[i].dis=ra();
e[i].day=i;
}
sort(e+1,e+m+1,cmp);
for(int i=1;i<=m;i++)
for(int j=1;j<=n;j++)fa[i][j]=j;
for(int i=1;i<=m;i++)
{
int day=e[i].day;
for(int j=day;j<=m;j++)
{
int aa=find(j,e[i].to);
int bb=find(j,e[i].f);
if(aa!=bb)
{
fa[j][aa]=bb;
total[j]++;
ans[j]+=e[i].dis;
}
}
}
/* for(int i=1;i<=m;i++)cout<<total[i]<<' ';
cout<<endl;
for(int i=1;i<=m;i++)cout<<ans[i]<<' ';
cout<<endl;*/
for(int i=1;i<=m;i++)
{
if(total[i]<n-1)printf("-1\n");
else printf("%d\n",ans[i]);
}
return 0;
}