首先明确一点:严格次小生成树与最小生成树有且只有一条边不同。
证明比较显然,自己画画图就行了,因为能替换的一定会构成一个环,依据这个就可以推出来。
同样,根据上面这个结论,我们可以枚举所有边,如果这条边不在生成树上,那么如果将这条边加入生成树中一定就会构成一个环,这时候只用将环上最大边删去即可,但考虑到严格次小生成树并且最大边可能与当前边权值相同,所以还要记录次大值。
所以相当于我们要询问最小生成树上两点之间路径的最大值或次大值,直接树剖即可。
#include
using namespace std;
typedef long long LL;
const int MAXN=1e5+10;
const int MAXM=3e5+10;
const int INF=0x3f3f3f3f;
int n,m,cnt=1;
LL val;
int fat[MAXN],a[MAXN];
int head[MAXN],depth[MAXN],fa[MAXN],son[MAXN],siz[MAXN],top[MAXN];
int nxt[MAXM],to[MAXM];
int w[MAXM];
int dfn[MAXN],ys[MAXN],tot;
struct Edge{
int u,v,w;
int used;
friend inline bool operator<(const Edge &a,const Edge &b){
return a.w'9'||c<'0')&&c!='-';c=getchar());
if(c=='-')
f=-1,c=getchar();
for(;c>='0'&&c<='9';c=getchar())
i=(i<<3)+(i<<1)+c-'0';
return i*f;
}
int find(int x){
if(x==fat[x])
return x;
return fat[x]=find(fat[x]);
}
void add(int x,int y,int z){
nxt[cnt]=head[x];
head[x]=cnt;
to[cnt]=y;
w[cnt]=z;
++cnt;
}
void kruskal(){
sort(edge+1,edge+m+1);
for(int i=1;i<=n;++i)
fat[i]=i;
int sum=0,u,v,fu,fv;
for(int i=1;i<=m;++i){
u=edge[i].u,v=edge[i].v;
fu=find(u),fv=find(v);
if(fu!=fv){
add(u,v,edge[i].w),add(v,u,edge[i].w);
fat[fu]=fv;
val+=edge[i].w;
++sum;
edge[i].used=1;
if(sum==n-1)
break;
}
}
}
void dfs1(int u,int f){
siz[u]=1;
int v;
for(int i=head[u];i;i=nxt[i]){
v=to[i];
if(v==f)
continue;
fa[v]=u;
depth[v]=depth[u]+1;
a[v]=w[i];
dfs1(v,u);
siz[u]+=siz[v];
if(siz[v]>siz[son[u]])
son[u]=v;
}
}
void dfs2(int u,int tp){
top[u]=tp;
dfn[u]=++tot;
ys[tot]=u;
if(!son[u])
return ;
dfs2(son[u],tp);
int v;
for(int i=head[u];i;i=nxt[i]){
v=to[i];
if(v==fa[u]||v==son[u])
continue;
dfs2(v,v);
}
}
void push_up(int root){
tr[root].maxx=max(tr[root<<1].maxx,tr[root<<1|1].maxx);
if(tr[root<<1].maxx==tr[root<<1|1].maxx)
tr[root].sec=max(tr[root<<1].sec,tr[root<<1|1].sec);
else
tr[root].sec=min(tr[root<<1].maxx,tr[root<<1|1].maxx);
}
void build(int root,int l,int r){
tr[root].l=l,tr[root].r=r;
if(l==r){
tr[root].maxx=a[ys[l]];
return ;
}
int mid=l+r>>1;
build(root<<1,l,mid);
build(root<<1|1,mid+1,r);
push_up(root);
}
int query(int root,int L,int R,int key){
if(tr[root].l>R||tr[root].r>1;
if(R<=mid)
return query(root<<1,L,R,key);
else{
if(L>mid)
return query(root<<1|1,L,R,key);
else
return max(query(root<<1,L,mid,key),query(root<<1|1,mid+1,R,key));
}
}
int querypath(int x,int y,int key){
int ret=0;
while(top[x]!=top[y]){
if(depth[top[x]]