给出一个图,求使得这个图中每个点的度数都为奇数。
求出用前i条边,使图满足条件的情况下,最大边权的最小值。
很容易发现一些性质:
如果要使得图中每个点度数为奇数,那么每个联通块中点的个数一定为偶数:
根据题目,为了使最大边权最小,我们可以把每个联通块看成它的最小生成树,那么这棵树一定满足:每个非根节点的儿子结点个数必须为偶数,根节点儿子结点个数必为奇数。否则就会出现度数为奇的情况。
那么我们可以这么考虑:首先根节点的儿子结点个数为奇,那么加上他自己,与根节点直接相连的点的个数就为偶数。每个非根结点都会为树增加偶数个子节点,所以最终整个树上的点一定为偶数个。
为了使图中的所有联通块大小都为偶数,
我们可以发现,加边是绝对无害的:
因为:奇数图+奇数图=偶数图,奇数图+偶数图=奇数图,偶数图+偶数图=偶数图。
所以可见我们要尽量加边。
当然,如果边的两端在同一联通块,我们就要找到环上的最大边权,与当前边权比较,看能否替换掉。
满足每个点度数都为奇数后,
为了使最大边权尽量小,我们也必须拆边,显然,拆边不能使图中生成奇数图,所以每次删去最大的边,再判断一次是否合法即可。
现在,我们需要动态地插边和删边,并询问路径上的最大边权,以及询问联通块大小。能做到的这些操作的数据结构,显然使用LCT。
#include
#include
#include
#include
#include
#define SF scanf
#define PF printf
using namespace std;
void Read(int &x){
char c;
bool flag=0;
while(c=getchar(),c!=EOF&&(c<'0'||c>'9')&&c!='-');
if(c=='-'){c=getchar();flag=1;}
x=c-'0';
while(c=getchar(),c!=EOF&&c>='0'&&c<='9')x=x*10+c-'0';
if(flag==1)x=-x;
}
#define MAXN 100010
#define MAXM 400010
namespace LCT{
int fa[MAXM],son[MAXM][2];
bool pre[MAXM],rev[MAXM];
int siz[MAXM],maxi[MAXM],val[MAXM],w[MAXM],sum[MAXM],mpos[MAXM];
void update(int x){
sum[x]=sum[son[x][0]]+sum[son[x][1]]+w[x];
siz[x]=siz[son[x][0]]+siz[son[x][1]]+1;
maxi[x]=val[x];
mpos[x]=x;
if(maxi[son[x][0]]>maxi[x])
maxi[x]=maxi[son[x][0]],mpos[x]=mpos[son[x][0]];
if(maxi[son[x][1]]>maxi[x])
maxi[x]=maxi[son[x][1]],mpos[x]=mpos[son[x][1]];
}
void flip(int x){
swap(son[x][0],son[x][1]);
rev[x]^=1;
}
void pushdown(int x){
if(rev[x]){
flip(son[x][0]);
flip(son[x][1]);
}
rev[x]=0;
}
void rotate(int x,int d){
int y=fa[x];
fa[x]=fa[y];
pre[x]=pre[y];
if(fa[y]&&pre[y])
son[fa[y]][son[fa[y]][1]==y]=x;
pre[y]=1;
son[y][!d]=son[x][d];
if(son[x][d])
fa[son[x][d]]=y;
son[x][d]=y;
fa[y]=x;
update(y);
update(x);
}
int sta[MAXM];
void splay(int x){
int y,z;
int pnt=0;
int x1=x;
while(pre[x1])
sta[++pnt]=x1,x1=fa[x1];
sta[++pnt]=x1;
for(int i=pnt;i>0;i--)
pushdown(sta[i]);
while(pre[x]){
y=fa[x];
z=fa[y];
if(!pre[y]){
rotate(x,son[y][0]==x);
break;
}
if((son[z][0]==y)==(son[y][0]==x)){
rotate(y,son[z][0]==y);
rotate(x,son[y][0]==x);
}
else{
rotate(x,son[y][0]==x);
rotate(x,son[z][0]==x);
}
}
if(rev[x])
flip(x);
update(x);
}
int Access(int x){
int last=0;
while(x){
splay(x);
pre[son[x][1]]=0;
fa[son[x][1]]=x;
w[x]+=sum[son[x][1]];
son[x][1]=last;
if(last)
pre[last]=1;
w[x]-=sum[last];
update(x);
last=x;
x=fa[last];
}
return last;
}
void MakeRoot(int x){
flip(Access(x));
splay(x);
rev[x]=!rev[x];
}
int FindRoot(int x){
Access(x);
splay(x);
int u=x;
while(son[u][0]){
pushdown(u);
u=son[u][0];
}
splay(u);
return u;
}
void Link(int x,int y){
if(FindRoot(x)==FindRoot(y))
return ;
flip(Access(x));
splay(x);
flip(Access(y));
splay(y);
fa[x]=y;
w[y]+=sum[x];
sum[y]+=sum[x];
Access(x);
}
void Change(int x,int y){
val[x]=y;
Access(x);
}
void Cut(int x){
Access(x);
splay(x);
pre[son[x][0]]=0;
fa[son[x][0]]=0;
son[x][0]=0;
update(x);
}
void Cut(int x,int y){
flip(Access(x));
Cut(y);
}
int Query(int x,int y){
flip(Access(x));
return maxi[Access(y)];
}
int Road(int x,int y){
flip(Access(x));
return mpos[Access(y)];
}
int Size(int x){
Access(x);
splay(x);
return sum[x];
}
}
using namespace LCT;
int lu[MAXM],lv[MAXM];
int odd,n,m;
void prepare(){
for(int i=1;i<=n+m;i++){
siz[i]=1;
if(i<=n)
w[i]=1,sum[i]=1;
}
}
void addedge(int idx){
int u=lu[idx];
int v=lv[idx];
if(Size(u)%2==1&&Size(v)%2==1) odd-=2;
Link(n+idx,u);
Link(n+idx,v);
}
int deledge(int idx){
int u=lu[idx];
int v=lv[idx];
Cut(n+idx,u);
Cut(n+idx,v);
//PF("(%d %d %d %d)\n",Size(u),Size(v),u,v);
if(Size(u)%2==1&&Size(v)%2==1) odd+=2;
return !(Size(u)%2);
}
setint ,int>,greaterint,int> > > q;
pair<int,int> l[MAXM];
int main(){
Read(n),Read(m);
prepare();
int x,y,wt;
odd=n;
for(int i=1;i<=m;i++){
Read(lu[i]),Read(lv[i]),Read(l[i].first);
l[i].second=i;
int u=lu[i];
int v=lv[i];
val[i+n]=maxi[i+n]=l[i].first;
if(FindRoot(u)==FindRoot(v)){
int qs=Road(u,v);
if(val[qs]>l[i].first){
deledge(qs-n);
addedge(i);
q.erase(q.find(make_pair(l[qs-n].first,qs-n)));
q.insert(l[i]);
//PF("{%d %d}\n",q.size(),q.begin()->id);
}
}
else{
addedge(i);
q.insert(l[i]);
}
//PF("(%d]\n",odd);
if(odd){
PF("-1\n");
continue;
}
while(deledge(q.begin()->second))
q.erase(q.begin());
addedge(q.begin()->second);
PF("%d\n",q.begin()->first);
}
}