题解 CF160D 【Edges in MST】

树链剖分写法

题意:给出n个点,m条边,问每条边的类型:

0:可能在最小生成树上

1:一定在最小生成树上

2:一定不在最小生成树上

首先造出一颗最小生成树,记录最小生成树上的最长边的边权val,然后可以将边分成三类:

①:树边(最小生成树上的边)

②:非树边且边权<=val

③:非树边且边权>val

对于第三类,答案一定为2,所以我们只需要考虑①与②。对于①,答案要么为0,要么为1;对于②,答案要么为0,要么为2

对于每条①边,其作用为连接两个端点分别所在的集合,如果存在一条②边,边长和作用皆与其相同,则该①边的答案为0,否则为1

对于每条②边,可代替的①边在且仅在两个端点的路径上(画个图就能理解了),所以用树链剖分+线段树维护每条①边可以被代替的最短②边边长

对于②边的答案,找出其能代替的最长①边的边长,用倍增维护即可

#include <bits/stdc++.h>
using namespace std;
#define LL long long
#define ls p<<1
#define rs p<<1|1
#define debug puts("debug");
const int M=1e5+5,P=1e9+7,base=269;
int n,m,totedge,head[M],faa[M],MX[M][18],vis[M],Mx,dep[M],tot,dfn[M],fa[M][18],top[M],son[M],sz[M],mi[M<<2],ans[M];
int find(int x){
	if(faa[x]==x)return x;
	return faa[x]=find(faa[x]);
}
struct EDGE{
	int x,y,val,id;
	bool operator < (const EDGE &_)const{
		return val<_.val;
	}
}B[M];
struct edge{
	int to,val,id,nxt;
}e[M<<1];
inline void add(int x,int y,int id,int v){
	e[++totedge]=(edge){y,v,id,head[x]};
	head[x]=totedge;
}
inline int rd(){
	int x=0;char c=getchar();
	while(!isdigit(c))c=getchar();
	while(isdigit(c))x=(x<<3)+(x<<1)+(c^48),c=getchar();
	return x;
}
void dfs(int x,int f){
	fa[x][0]=f,dep[x]=dep[f]+1,sz[x]=1;
	for(int i=1;i<=17;++i){
		fa[x][i]=fa[fa[x][i-1]][i-1];
		MX[x][i]=max(MX[x][i-1],MX[fa[x][i-1]][i-1]);
	}
	for(int i=head[x];i;i=e[i].nxt){
		int y=e[i].to;
		if(y==f)continue ;
		MX[y][0]=e[i].val;
		dfs(y,x);
		sz[x]+=sz[y];
		if(sz[son[x]]<sz[y])son[x]=y;
	}
}
void dfs2(int x,int tp){
	top[x]=tp;dfn[x]=++tot;
	if(son[x])dfs2(son[x],tp);
	for(int i=head[x];i;i=e[i].nxt){
		int y=e[i].to;
		if(y==fa[x][0]||y==son[x])continue ; 
		dfs2(y,y);
	}
}
int LCA(int x,int y){
	while(top[x]!=top[y]){
		if(dep[top[x]]>dep[top[y]])x=fa[top[x]][0];
		else y=fa[top[y]][0];
	}
	return dep[x]>dep[y]?y:x;
}
void build(int l,int r,int p){
	mi[p]=2e9;
	if(l==r)return ;
	int mid=l+r>>1;
	build(l,mid,ls);
	build(mid+1,r,rs);
}
void update(int l,int r,int L,int R,int v,int p){
	if(l>=L&&r<=R){
		mi[p]=min(mi[p],v);
		return ;
	}
	int mid=l+r>>1;
	if(L<=mid)update(l,mid,L,R,v,ls);
	if(R>mid)update(mid+1,r,L,R,v,rs);
}
void Pre_update(int a,int b,int v,int id){
	int lca=LCA(a,b),now,mx=0;
	now=a;
	for(int i=17;~i;--i){
		if(dep[fa[now][i]]>=dep[lca]){
			mx=max(mx,MX[now][i]);
			now=fa[now][i];
		}
	}
	while(top[a]!=top[lca]){
		update(1,n,dfn[top[a]],dfn[a],v,1);
		a=fa[top[a]][0];
	}
	if(a!=lca)update(1,n,dfn[lca]+1,dfn[a],v,1);
	now=b;
	for(int i=17;~i;--i){
		if(dep[fa[now][i]]>=dep[lca]){
			mx=max(mx,MX[now][i]);
			now=fa[now][i];
		}
	}
	while(top[b]!=top[lca]){
		update(1,n,dfn[top[b]],dfn[b],v,1);
		b=fa[top[b]][0];
	}
	if(b!=lca)update(1,n,dfn[lca]+1,dfn[b],v,1);
	if(mx>=v)ans[id]=0;
	else ans[id]=2;
}
int query(int x,int l,int r,int res,int p){
	res=min(res,mi[p]);
	if(l==r)return res;
	int mid=l+r>>1;
	if(x<=mid)return query(x,l,mid,res,ls);
	return query(x,mid+1,r,res,rs);
}
void dfs3(int x,int f){
	for(int i=head[x];i;i=e[i].nxt){
		int y=e[i].to;
		if(y==f)continue ;
		int tmp=query(dfn[y],1,n,2e9,1);
		if(tmp>e[i].val)ans[e[i].id]=1;
		else ans[e[i].id]=0;
		dfs3(y,x);
	}
}
int main(){
	freopen("mstagain.in","r",stdin);
	freopen("mstagain.out","w",stdout);
	int a,b;
	n=rd(),m=rd();
	for(int i=1;i<=n;++i)faa[i]=i;
	for(int i=1;i<=m;++i){
		B[i].x=rd(),B[i].y=rd(),B[i].val=rd();
		B[i].id=i;
	}	
	sort(B+1,B+m+1);	
	for(int i=1;i<=m;++i){
		a=find(B[i].x),b=find(B[i].y);
		if(a==b)continue ;
		vis[i]=1;
		faa[a]=b;
		add(B[i].x,B[i].y,B[i].id,B[i].val);
		add(B[i].y,B[i].x,B[i].id,B[i].val);
		Mx=B[i].val;
	}
	dfs(1,0);
	dfs2(1,1);
	build(1,n,1);
	for(int i=1;i<=m;++i){
		if(vis[i])continue ;
		if(B[i].val>Mx){
			ans[B[i].id]=2;
			continue ;
		}
		Pre_update(B[i].x,B[i].y,B[i].val,B[i].id);
	}
	dfs3(1,0);
	for(int i=1;i<=m;++i){
		printf("%d\n",ans[i]);
	}
	return 0;
}



posted @ 2021-06-02 19:32  We269  阅读(136)  评论(0)    收藏  举报