[CSP-S模拟测试]:weight(Kruskal+树链剖分)
题目描述
给你一个$n$个点$m$条边的带边权的无向图(无重边,无自环),现在对于每条边,问你这条边的权值最大可以是多大,使得这条边在无向图的所有最小生成树中?(边权都是整数)。
输入格式
第一行包含三个整数$n,m,a$表示点数和边数及特殊性质标记(如果$a=0$表示没有特殊性质,如果殊性质)。
接下来$m$行每行包含三个整数$u,v,w$表示有一条$u$和$v$之间的边,且边权为$w$。
输出格式
输出一行,包含$m$个数,第$i$个数表示第$i$条边对应的答案(如果某条边的权值可以取到$+\infty$输出$-1$)。
样例
样例输入1:
4 4 0
1 2 1
2 3 1
3 4 1
4 1 2
样例输出1:
1 1 1 0
样例输入2:
4 3 0
1 2 2
2 3 2
3 4 2
样例输出2:
-1 -1 -1
数据范围与提示
特殊性质:$w=1$(对于所有边);
对于所有数据:$1\leqslant u,v\leqslant n,1\leqslant w\leqslant {10}^9$。
题解
对于一条边,分为两种情况:
$\alpha.$最小生成树上的边,那么它的最大值就是能代替它的最小边的边权$-1$。
$\beta.$不是最小生成树上的边,那么它的最大值就是最小生成树上那条边的边权$-1$。
对于如何求,用树链剖分就好了,代码稍长……
数据的输出有点问题,如果不在$1$节点的联通块中则输出$0$。
时间复杂度:$\Theta(n\log^2 n)$。
期望得分:$100$分。
实际得分:$100$分。
代码时刻
#include<bits/stdc++.h>
#define L(x) x<<1
#define R(x) x<<1|1
using namespace std;
struct node{int fr,to,w,id;bool tr;}b[100001];
struct rec{int nxt,to,w,id;}e[200001];
int head[70001],cnt;
int maxb,dy[70001];
int n,m,a;
int f[70001];
int depth[70001],size[70001],id[70001],w[70001],son[70001],top[70001],pos[70001],fa[70001];
int trmax[280001],trmin[280001],lz[280001];
int ans[100001];
bool cmp(node a,node b){return a.w<b.w;}
void add(int x,int y,int w,int id)
{
e[++cnt].nxt=head[x];
e[cnt].to=y;
e[cnt].w=w;
e[cnt].id=id;
head[x]=cnt;
}
int find(int x){return x==f[x]?x:f[x]=find(f[x]);}
void pre_dfs(int x)
{
size[x]=1;
for(int i=head[x];i;i=e[i].nxt)
if(e[i].to!=fa[x])
{
depth[e[i].to]=depth[x]+1;
fa[e[i].to]=x;
dy[e[i].to]=e[i].id;
w[e[i].to]=e[i].w;
pre_dfs(e[i].to);
size[x]+=size[e[i].to];
if(size[e[i].to]>size[son[x]])son[x]=e[i].to;
}
}
void pro_dfs(int x,int tp)
{
top[x]=tp;
id[x]=++cnt;
pos[cnt]=x;
if(son[x])pro_dfs(son[x],tp);
for(int i=head[x];i;i=e[i].nxt)
if(e[i].to!=fa[x]&&e[i].to!=son[x])pro_dfs(e[i].to,e[i].to);
}
void build(int x,int l,int r)
{
trmin[x]=lz[x]=maxb+1;
if(l==r)
{
trmax[x]=w[pos[l]];
return;
}
int mid=(l+r)>>1;
build(L(x),l,mid);
build(R(x),mid+1,r);
trmax[x]=max(trmax[L(x)],trmax[R(x)]);
}
void pushdown(int x)
{
if(lz[x]==maxb+1)return;
trmin[L(x)]=min(trmin[L(x)],lz[x]);
trmin[R(x)]=min(trmin[R(x)],lz[x]);
lz[L(x)]=min(lz[L(x)],lz[x]);
lz[R(x)]=min(lz[R(x)],lz[x]);
lz[x]=1<<30;
}
int ask(int x,int l,int r,int L,int R)
{
if(R<l||r<L)return 0;
if(L<=l&&r<=R)return trmax[x];
int mid=(l+r)>>1;
return max(ask(L(x),l,mid,L,R),ask(R(x),mid+1,r,L,R));
}
int query(int x,int y)
{
int ret=0;
while(top[x]!=top[y])
{
if(depth[top[x]]<depth[top[y]])swap(x,y);
ret=max(ret,ask(1,1,n,id[top[x]],id[x]));
x=fa[top[x]];
}
if(depth[x]>depth[y])swap(x,y);
if(id[x]<id[y])ret=max(ret,ask(1,1,n,id[x]+1,id[y]));
return ret;
}
void change(int x,int l,int r,int L,int R,int w)
{
if(R<l||r<L)return;
if(L<=l&&r<=R)
{
trmin[x]=min(trmin[x],w);
lz[x]=min(lz[x],w);
return;
}
int mid=(l+r)>>1;
pushdown(x);
change(L(x),l,mid,L,R,w);
change(R(x),mid+1,r,L,R,w);
trmin[x]=min(trmin[L(x)],trmin[R(x)]);
}
int update(int x,int y,int w)
{
int ret=0;
while(top[x]!=top[y])
{
if(depth[top[x]]<depth[top[y]])swap(x,y);
change(1,1,n,id[top[x]],id[x],w);
x=fa[top[x]];
}
if(depth[x]>depth[y])swap(x,y);
if(id[x]<id[y])change(1,1,n,id[x]+1,id[y],w);
return ret;
}
void getans(int x,int l,int r)
{
if(l==r)
{
ans[dy[pos[l]]]=trmin[x];
if(ans[dy[pos[l]]]==maxb+1)ans[dy[pos[l]]]=0;
ans[dy[pos[l]]]--;
return;
}
int mid=(l+r)>>1;
pushdown(x);
getans(L(x),l,mid);
getans(R(x),mid+1,r);
}
int main()
{
scanf("%d%d%d",&n,&m,&a);
for(int i=1;i<=n;i++)f[i]=i;
for(int i=1;i<=m;i++)
{
int x,y,w;
scanf("%d%d%d",&x,&y,&w);
b[i]=(node){x,y,w,i,0};
maxb=max(maxb,w);
}
sort(b+1,b+m+1,cmp);
for(int i=1;i<=m;i++)
if(find(b[i].fr)!=find(b[i].to))
{
f[find(b[i].fr)]=find(b[i].to);
add(b[i].fr,b[i].to,b[i].w,b[i].id);
add(b[i].to,b[i].fr,b[i].w,b[i].id);
b[i].tr=1;
}
cnt=0;
pre_dfs(1);
pro_dfs(1,1);
build(1,1,n);
for(int i=1;i<=m;i++)
if(!b[i].tr)
{
ans[b[i].id]=query(b[i].fr,b[i].to)-1;
update(b[i].fr,b[i].to,b[i].w);
}
getans(1,1,n);
for(int i=1;i<=m;i++)printf("%d ",ans[i]);
return 0;
}
rp++