[解题记录] P4374 [USACO18OPEN]Disruption P

P4374 [USACO18OPEN]Disruption P#

题意简述#

给定一颗树几条额外的边(保证每两个点之间只有一条边),求对于原有的所有边去掉之后,能够重新连接树的最短的替代用道路的长度,如果不存在合适的替代用的道路,输出 1


解题思路#

可以发现,由于一开始的图是树那么加上一条额外的边后,就一定能形成一个环,对于环上的每一条边,如果这条边去掉了都可以用环中额外的边去代替,并且有一个显然的性质,一条额外的边只对它所在环上的边起作用,那么对于每条额外的边,我们都可以用它来更新环上所有边可代替的最小值,这显然可以用线段树和树剖去维护


Code#

#include <bits/stdc++.h>
#define ls p<<1
#define rs p<<1|1
using namespace std;
inline int read(){
    int x=0,f=1;char ch=getchar();
    while(ch>'9'||ch<'0'){if(ch=='-')f=-1;ch=getchar();}
    while(ch>='0'&&ch<='9'){x=(x<<1)+(x<<3)+ch-'0';ch=getchar();}
    return x*f;
}
const int N=4e5+10,INF=1e9+10;
int ver[N],tot,nxt[N],head[N];
int fa[N],dep[N],dfn[N],top[N],sz[N],dfstime,son[N];
int lazy[N],ret[N],n,m,U[N],V[N];
void add(int x,int y){
    ver[++tot]=y,nxt[tot]=head[x],head[x]=tot;
    ver[++tot]=x,nxt[tot]=head[y],head[y]=tot;
}
void dfs1(int u,int father){
    fa[u]=father;dep[u]=dep[father]+1;sz[u]=1;
    for(int i=head[u];i;i=nxt[i]){
	int v=ver[i];
	if(v==fa[u]) continue;
	dfs1(v,u);
	sz[u]+=sz[v];
	if(sz[v]>sz[son[u]]) son[u]=v;
    }
}
void dfs2(int u,int anc){
    top[u]=anc;dfn[u]=++dfstime;
    if(son[u]) dfs2(son[u],anc);
    for(int i=head[u];i;i=nxt[i]){
	int v=ver[i];
	if(top[v]) continue;
	dfs2(v,v);
    }
}
void pushup(int p){
    ret[p]=min(ret[ls],ret[rs]);
    return;
}
void down(int p){
    if(lazy[p]==INF) return;
    lazy[ls]=min(lazy[ls],lazy[p]);
    lazy[rs]=min(lazy[rs],lazy[p]);
    ret[ls]=min(ret[ls],lazy[p]);
    ret[rs]=min(ret[rs],lazy[p]);
    lazy[p]=INF;
}
void build(int p,int l,int r){
    lazy[p]=ret[p]=INF;
    if(l==r) return;
    int mid=(l+r)>>1;
    build(ls,l,mid);
    build(rs,mid+1,r);
}
int query(int p,int l,int r,int x){
    if(l==r) return ret[p];
    down(p);
    int mid=(l+r)>>1;
    if(x<=mid) return query(ls,l,mid,x);
    else return query(rs,mid+1,r,x);
}
void upd(int p,int l,int r,int x,int y,int z){
    if(x<=l&&y>=r){
	ret[p]=min(ret[p],z);
	lazy[p]=min(lazy[p],z);
	return;
    }
    down(p);
    int mid=(l+r)>>1;
    if(x<=mid) upd(ls,l,mid,x,y,z);
    if(y>mid)  upd(rs,mid+1,r,x,y,z);
    pushup(p);
}
void chainupd(int x,int y,int z){
    while(top[x]!=top[y]){
	if(dep[top[x]]<dep[top[y]]) swap(x,y);
	upd(1,1,n,dfn[top[x]],dfn[x],z);
	x=fa[top[x]];
    }
    if(dep[x]>dep[y]) swap(x,y);
    upd(1,1,n,dfn[x]+1,dfn[y],z);
    return;
}
int main(){
    n=read();m=read();
    for(int i=1;i<n;++i){
	U[i]=read();V[i]=read();
	add(U[i],V[i]);
    }
    dfs1(1,0);
    dfs2(1,1);
    build(1,1,n);
    for(int i=1;i<=m;++i){
	int x=read(),y=read(),z=read();
	chainupd(x,y,z);
    }
    for(int i=1;i<n;++i){
	int x=U[i],y=V[i];
	if(dep[x]<dep[y]) swap(x,y);
	int ans=query(1,1,n,dfn[x]);
	if(ans==INF) puts("-1");
	else printf("%d\n",ans);
    }
    return 0;
}

posted @   Miraii  阅读(42)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 25岁的心里话
· 按钮权限的设计及实现
点击右上角即可分享
微信分享提示
主题色彩