Description
Sample Input
样例输入 1:
4 4
1 3 4
2 4 8
1 2 2
3 4 3
样例输入 2:
3 2
1 2 3
2 3 4
Sample Output
样例输出 1:
-1
8
8
3
样例输出 2:
-1
-1
Data Constraint
首先,答案是单调不增的
并且容易证出,所有联通块大小为偶数
对于只回答最后一组询问,把边权排序,直到没有大小是技术的联通块就行
现在要推广到所有询问
考虑将时间看为x,边权看为y,这么看一条边就是平面上一个点。
将询问时间看为x,答案看为y,询问也变成了一个点。
我们就可以用分治乱搞。
#include
using namespace std;
const int N=3e5+77;
int n,m;
int sz[N],fa[N],cnt,rk[N];
int ans[N];
struct E
{
int x,y,w,id;
}e[N];
bool cmp(E a,E b){return a.w<b.w;}
int fi;
vector<E> b[N*4];
multiset<int> em;
int gf(int x)
{
return fa[x]==0?x:gf(fa[x]);
}
struct yjy
{
int x,y,w,irs;
};
stack<yjy> S;
void ins(int x,int l,int r,int tl,int tr,const E &a)
{
if(l>tr||r<tl) return;
if(tl<=l&&r<=tr)
{
b[x].push_back(a); return;
}
ins(x<<1,l,l+r>>1,tl,tr,a);
ins(x<<1|1,(l+r>>1)+1,r,tl,tr,a);
}
void merge(E e)
{
int x=gf(e.x),y=gf(e.y);
if(rk[x]>rk[y])swap(x,y);
if(x!=y)
{
em.insert(e.w);
yjy a=(yjy){x,y,e.w,rk[x]==rk[y]};
S.push(a);
fa[x]=y;
if(rk[y]==rk[x])rk[y]++;
if((sz[y]&1)&&(sz[x]&1))cnt-=2;
sz[y]+=sz[x];
}
else S.push((yjy){0,0,0,0});
}
void pop()
{
yjy a=S.top();S.pop();
if(a.x==0)return;
sz[a.y]-=sz[a.x];
fa[a.x]=0;
if(a.irs) rk[a.y]--;
em.erase(em.find(a.w));
if((sz[a.y]&1)&&(sz[a.x]&1)) cnt+=2;
}
void work(int x,int l,int r)
{
for(E t:b[x]) merge(t);
if(l==r)
{
int LF=fi;
if(cnt!=0)
{
int i=fi+1;
for(;i<=m;i++)
{
if(cnt==0)break;
if(e[i].id<=l)
{
merge(e[i]);
ins(1,1,m,e[i].id,l-1,e[i]);
}
}
fi=i-1;
}
if(cnt==0)ans[l]=*em.rbegin();
for(int i=fi; i>LF; i--)if(e[i].id<=l)pop();
}
else
{
work(x<<1|1,(l+r>>1)+1,r);
work(x<<1,l,l+r>>1);
}
for(int i=0; i<b[x].size(); i++)
pop();
}
int main()
{
freopen("road.in","r",stdin);
freopen("road.out","w",stdout);
cin>>n>>m;
for(int i=1,x,y,w; i<=m; i++)
{
scanf("%d%d%d",&x,&y,&w);
e[i]=(E){x,y,w,i};
}
sort(e+1,e+1+m,cmp);
for(int i=1; i<=n; i++) sz[i]=1;cnt=n;
work(1,1,m);
for(int i=1; i<=m; i++) if(ans[i]==0) printf("%d\n",-1);
else printf("%d\n",ans[i]);
}