让我想起了徐州的第一题。。。。还以为比那题更难
第二天早上队友跟我聊了下这题,然后我发现这题就可以用我徐州第一题的错误的思路做(虽然那题因为数据特殊性A了。。。),我们开两个并查集,对于一段相同的边,f1表示这段相同的边之前的连接情况,然后从前向后枚举这段边,如果能连就连,只更新f2,如果不能连,去f1中看看是不是在同一集合,如果不在,说明这段边中在这条边之前有一条边跟这条边是等价的,这样就会形成多棵最小生成树,需要把一条边+1,而吧这条边+1,对之后也没有影响。
之后再把f2的更新情况同步到f1中去
#include<bits/stdc++.h>
#define maxl 200010
using namespace std;
int n,m,ans;
int f1[maxl],f2[maxl];
struct ed
{
int u,v,val;
}e[maxl];
struct node
{
int ind,val;
};
vector <node> tmp;
bool cmp(const ed &x,const ed&y)
{
return x.val<y.val;
}
inline void prework()
{
scanf("%d%d",&n,&m);
for(int i=1;i<=m;i++)
scanf("%d%d%d",&e[i].u,&e[i].v,&e[i].val);
for(int i=1;i<=n;i++)
f1[i]=i,f2[i]=i;
sort(e+1,e+1+m,cmp);
}
inline int find1(int x)
{
if(f1[x]!=x)
f1[x]=find1(f1[x]);
return f1[x];
}
inline int find2(int x)
{
if(f2[x]!=x)
f2[x]=find2(f2[x]);
return f2[x];
}
inline void mainwork()
{
int xx,yy,x,y,nxt;
for(int i=1;i<=m;i++)
{
nxt=i;
while(e[nxt+1].val==e[nxt].val && nxt<m)
nxt++;
tmp.clear();
for(int j=i;j<=nxt;j++)
{
xx=find2(e[j].u);yy=find2(e[j].v);
if(xx!=yy)
{
f2[yy]=xx;
tmp.push_back(node{yy,xx});
}
else
{
x=find1(e[j].u);y=find1(e[j].v);
if(x!=y)
ans++;
}
}
int l=tmp.size();
for(int j=0;j<l;j++)
{
f1[tmp[j].ind]=tmp[j].val;
find1(tmp[j].ind);
}
for(int j=i;j<=nxt;j++)
find1(e[j].u),find1(e[j].v);
i=nxt;
}
}
inline void print()
{
printf("%d",ans);
}
int main()
{
prework();
mainwork();
print();
return 0;
}