标签:最小生成树,并查集
小B准备设计施工方案。
设计图是一个n个点m条边的图,小B每次施工可以取图中一个还没有完工的生成森林把它完工。
为了加快施工效率,每次取的时候小B都会最大化当前这个生成森林的边数。请你帮他找出一个符合要求的施工方案。
如果有多个方案,输出任意一种即可。
输入格式
第一行两个整数n, m。
后面m行,每行两个数ai,bi表示一条边,保证没有自环。
输出格式
m行,每行一个整数,表示这条边属于第几次。如果有多个方案,输出任意一种即可。
样例一
input
5 7
1 2
2 3
3 4
4 5
1 2
2 3
1 2
output
1
1
1
1
3
2
2
限制与约定
分析
每条边加入图中,维护若干个森林,每条边都加入到第一个两个端点不连通的森林中
每一个生成森林都用并查集来维护,二分出第一个两端点不连通的并查集
时间复杂度为O(m log m*a(n))
Code
#include<bits/stdc++.h>
#define rep(i,a,b) for(int i=a;i<=b;i++)
#define dep(i,a,b) for(int i=a;i>=b;i--)
#define reg(i,a) for(int i=u[a];i;i=e[i].pre)
#define v e[i].to
#define LL long long
using namespace std;
const int maxn=1e6+10;
inline int read()
{int f=1,x=0;char ch=getchar();while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}return x*f;
}
struct edge{int to,pre;}e[maxn<<1];
int u[maxn],l=1;
inline void ins(int a,int b){e[++l]=(edge){b,u[a]},u[a]=l;}
int id[maxn],n,m;
int pre[maxn*2],nxt[maxn*2],mx=0,r[maxn];
bool vis[maxn];
int del(int x){nxt[pre[x]]=nxt[x];pre[nxt[x]]=pre[x];
}
void insert(int x,int r){pre[x]=maxn+r,nxt[x]=nxt[maxn+r];pre[nxt[x]]=nxt[pre[x]]=x;
}
void add(int x) {del(x);r[x]++; mx = max(mx, r[x]);insert(x, r[x]);
}
void Forest(){rep(i,1,n)insert(i,0);rep(i,1,n){while(!nxt[maxn+mx])mx--;int x=nxt[maxn+mx];del(x);vis[x]=true;reg(i,x) if(!vis[v]) id[i>>1]=r[v]+1,add(v);}
}int main()
{n=read(),m=read();rep(i,1,m){int a=read(),b=read();ins(a,b),ins(b,a);}Forest();rep(i,1,m) printf("%d\n",id[i]);return 0;
}