/*
染色+二分
把每名罪犯看成一个点,然后2个人有仇恨就连一条边权为他们仇恨值的边
最后要求的时候,把这个图分成2部分,然后使的这2部份内部可能有的值中最大值最小
首先会想到二分图,如果这个图是一个二分图的话,那么答案是0
如果不是二分图的话,就要找到最优的划分,让最大值最小
假想现在有一个图,先把他划分为2分图的形式,但是2个部分内部也是有边的,那么我们要找的答案就是内部边的最大值
也就是说内部的边破坏了这个图的2分性质,如果去掉这些边,这个图就可以变成一个二分图
那么就可以用去边的方式来找最大值,当某一组边去掉后,这个图变成的二分图,那么这一组的最大值,就是一个待参考答案
我们要找的是最大值的最小值,就可以用二分,首先把输入的边权按照升序排序
然后我们对边权进行二分,从中取出一个边权,然后去掉小于等于他的边,如果能使这个图变成二分图,那么成立
证明二分成立:
1,当去掉边权不超过m的边后,二分图成立的话,那么这个m值就是这组边的最大值,因为找的是最小值,那么比他大的那些组的边就不用看了
2.当二分图不成立的时候,就表示不超过m的边删除后,还要继续删除边才可以构成二分图,所以比他小的也就不用看了
还一个二分图,不管怎么删除边,他还是二分图
*/
#include<iostream>
#include<cstring>
#include<algorithm>
using namespace std;
const int N=20010,M=200010;
int n,m;
int ne[M],val[M],h[N],w[M],indx;
int quan[M],color[N];
bool dfs(int x,int se,int t)
{
color[x]=se;
for(int i=h[x];i!=-1;i=ne[i])
{
if(w[i]>t)
{
int j=val[i];
if(!color[j])
{
if(!dfs(j,3-se,t)) return false;
}
else if(color[j]==se) return false;
}
}
return true;
}
bool check(int x)
{
memset(color,0,sizeof color);
for(int i=1;i<=n;i++)
{
if(!color[i])
{
if(!dfs(i,1,x)) return false;
}
}
return true;
}
void add(int x,int y,int z)
{
val[indx]=y,ne[indx]=h[x],w[indx]=z,h[x]=indx++;
}
int main()
{
cin>>n>>m;
memset(h,-1,sizeof h);
for(int i=1;i<=m;i++)
{
int x,y,z;
cin>>x>>y>>z;
add(x,y,z);
add(y,x,z);
quan[i]=z;
}
sort(quan+1,quan+m+1);
int l=0,r=m;//这里l从0开始,因为可能不用删除边也可能是二分图
while(l<r)
{
int mid=l+r>>1;
if(check(quan[mid])) r=mid;
else l=mid+1;
}
cout<<quan[r]<<endl;
return 0;
}