• 题意:一个无向图,每次询问给出一条边,问这条边的最大值满足这条边一定在这个图的最小生成树上,如果没有上限输出-1。
  • 思路:考场上想过的,将分为两类,(非)树边。

1.亿点性质

  • 非树边:加上这条边所构成的环上的边都可能替代它,所以它应该是两点树上路径max-1
  • 树边:若树边在非树边两端点的路径上,则该非树边可能更新该树边。而树边应该为所有能更新它的非树边min-1。

2.解法

  • 费树边:倍增记录mx
  • 树边:路径覆盖并查集(自己取名的qaq),枚举所有非树边,暴力往上跳,更新路径上的树边最小值
    ??TLE!!肯定不能暴力!
    先将非树边按边权从小到大排序,所以一条树边只会被更新一次。中间我们维护一个新的并查集,一条边被更新后直接将边的根指到自己的父亲的根(下次就直接get_fa不会经过该点了,并查集还要路径压缩cj快!)

3.代码:写了半个晚自习:

#include<bits/stdc++.h>
using namespace std;

static char buf[1000000],*p1=buf,*p2=buf,obuf[1000000],*p3=obuf;
#define getchar() p1==p2&&(p2=(p1=buf)+fread(buf,1,1000000,stdin),p1==p2)?EOF:*p1++
#define putchar(x) (p3-obuf<1000000)?(*p3++=x):(fwrite(obuf,p3-obuf,1,stdout),p3=obuf,*p3++=x)
template<typename item>
inline void read(register item &x)
{
    x=0;register char c=getchar();
    while(c<'0'||c>'9')c=getchar();
    while(c>='0'&&c<='9')x=(x<<3)+(x<<1)+(c^48),c=getchar();
}
const int N=1e6+5;
const int M=2e6+5;
struct edge {int x,y,z,used,id;}E[M];
bool cmp(edge u,edge v) {return u.z<v.z;}
int ans[M],n,m,q,dep[N],ecnt,nxt[M],head[N],len[M],mn[M],to[M],fa[N],f[N][21],mx[N][21],inf=0x3f3f3f3f;
void add_edge(int u,int v,int w) {nxt[++ecnt]=head[u];to[ecnt]=v;len[ecnt]=w;head[u]=ecnt;}
int g_fa(int u) {return fa[u]==u?u:fa[u]=g_fa(fa[u]);}
void kruskal() {
	sort(E+1,E+1+m,cmp);
	for(int i=1;i<=n;i++) fa[i]=i;
	for(int i=1,j=1;i<=m&&j<n;i++) {
		int u=g_fa(E[i].x),v=g_fa(E[i].y);
		if(u!=v) {
			fa[u]=v;
			add_edge(E[i].x,E[i].y,E[i].z),add_edge(E[i].y,E[i].x,E[i].z);
			E[i].z=inf,E[i].used=1;
			j++;
		}
	}
}
void dfs(int u,int fa) {
	for(int i=head[u];i;i=nxt[i]) {
		int v=to[i];
		if(v==fa)continue;
		dep[v]=dep[u]+1;
		f[v][0]=u,mx[v][0]=len[i];
		for(int i=1;i<=19;i++) 
			f[v][i]=f[f[v][i-1]][i-1],mx[v][i]=max(mx[v][i-1],mx[f[v][i-1]][i-1]);
		dfs(v,u);
	}
}
int Lca(int u,int v) { 
	if(dep[u]<dep[v]) swap(u,v);
	int k=dep[u]-dep[v],res=0;
	for(int i=0;i<=19;i++)if((1<<i)&k) res=max(res,mx[u][i]),u=f[u][i];
	if(u==v) return res;
	for(int i=19;i>=0;i--) {
		if(f[u][i]!=f[v][i]) res=max(res,max(mx[u][i],mx[v][i])),u=f[u][i],v=f[v][i];
	} 
	return max(res,max(mx[u][0],mx[v][0]));
}
void work() {
	memset(mn,-1,sizeof(mn));
	sort(E+1,E+1+m,cmp);
	for(int i=1;i<=n;i++)fa[i]=i;
	for(int i=1;i<=m;i++) {
		if(E[i].used) continue;
		int u=E[i].x,v=E[i].y;
		while(u!=v) {
			if(dep[u]<dep[v]) swap(u,v);
			if(mn[u]==-1)mn[u]=E[i].z;
			int r=g_fa(f[u][0]);
			fa[u]=r,u=r;
		}
	}
}
void solve() {
	for(int i=1;i<=m;i++) {
		int u=E[i].x,v=E[i].y;
		if(dep[u]<dep[v]) swap(u,v);
		if(E[i].used) {
			if(mn[u]==-1) ans[E[i].id]=-1;
			else ans[E[i].id]=mn[u]-1;
		}
		else ans[E[i].id]=Lca(u,v)-1;
	}
}
int main() {
	read(n),read(m);
	for(int i=1;i<=m;i++) read(E[i].x),read(E[i].y),read(E[i].z),E[i].id=i;
	kruskal();
	dep[1]=1,dfs(1,0);
	work();
	solve();
	read(q);
	while(q--) {
		int s;
		read(s);
		printf("%d\n",ans[s]);
	}
	return 0;
}

ps.还有最近的题全要用fread的快读qwq……