题解 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;
}

浙公网安备 33010602011771号