如今开始正式填之前欠下的一些题解。就从这道经典的NOIp题开始讲吧。git
咱们仔细看题目,发现要求的是图上两点\((u,v)\)之间的路径上最小值的最大值。优化
跑DP?图上状态太多了,单次要\(O(n)\)的复杂度,直接T飞。spa
咱们考虑一种经典方法:将图转化为一颗树来作code
因为树保证联通,而这里要求最大化最小值,所以咱们很容易想到把最大瓶颈生成树找出来get
而后在树上维护信息?那么暴力树剖维护最大值?复杂度双\(log\)。有点危险。string
再优化一波,咱们用树上倍增和维护倍增LCA的方法同样维护最大值,对于全部询问的两个点直接一块儿跳到它们的LCA便可it
注意图可能不连通,不过咱们前面的并查集就能够直接用来判连通性了。io
CODEclass
#include<cstdio> #include<cctype> #include<algorithm> #include<cstring> using namespace std; const int N=10005,P=15; struct data { int l,r,s; }a[N*5]; int head[N],n,m,q,x,y,father[N],dep[N],par[N][P],f[N][P],cnt; bool use[N]; struct edge { int to,next,v; }e[N<<1]; inline char tc(void) { static char fl[100000],*A=fl,*B=fl; return A==B&&(B=(A=fl)+fread(fl,1,100000,stdin),A==B)?EOF:*A++; } inline void read(int &x) { x=0; char ch; while (!isdigit(ch=tc())); while (x=(x<<3)+(x<<1)+ch-'0',isdigit(ch=tc())); } inline void write(int x) { if (x>9) write(x/10); putchar(x%10+'0'); } inline int getfather(int k) { return father[k]^k?father[k]=getfather(father[k]):k; } inline bool cmp(data a,data b) { return a.s>b.s; } inline void double_add(int x,int y,int z) { e[++cnt].to=y; e[cnt].next=head[x]; e[cnt].v=z; head[x]=cnt; e[++cnt].to=x; e[cnt].next=head[y]; e[cnt].v=z; head[y]=cnt; } inline int min(int a,int b) { return a<b?a:b; } inline void MST(void) { for (register int i=1;i<=n;++i) father[i]=i; for (register int i=1;i<=m;++i) { int fx=getfather(a[i].l),fy=getfather(a[i].r); if (fx!=fy) double_add(a[i].l,a[i].r,a[i].s),father[fx]=fy; } } inline void reset(int now) { for (register int i=0;i<P-1;++i) if (par[now][i]) par[now][i+1]=par[par[now][i]][i],f[now][i+1]=min(f[now][i],f[par[now][i]][i]); else break; } inline void DFS(int now,int fa,int d) { dep[now]=d; par[now][0]=fa; reset(now); for (register int i=head[now];i!=-1;i=e[i].next) if (e[i].to!=fa) f[e[i].to][0]=e[i].v,DFS(e[i].to,now,d+1); } inline void swap(int &a,int &b) { int t=a; a=b; b=t; } inline int get_min(int x,int y) { int res=1e9; if (dep[x]<dep[y]) swap(x,y); for (register int i=P-1;i>=0;--i) if (par[x][i]&&dep[par[x][i]]>=dep[y]) res=min(res,f[x][i]),x=par[x][i]; if (x==y) return res; for (register int i=P-1;i>=0;--i) if (par[x][i]!=par[y][i]) { res=min(res,min(f[x][i],f[y][i])); x=par[x][i]; y=par[y][i]; } return min(res,min(f[x][0],f[y][0])); } int main() { //freopen("CODE.in","r",stdin); freopen("CODE.out","w",stdout); register int i; read(n); read(m); memset(head,-1,sizeof(head)); memset(e,-1,sizeof(e)); for (i=1;i<=m;++i) read(a[i].l),read(a[i].r),read(a[i].s); sort(a+1,a+m+1,cmp); MST(); read(q); for (i=1;i<=n;++i) { int fa=getfather(i); if (!use[fa]) DFS(i,0,0),use[fa]=1; } while (q--) { read(x); read(y); if (getfather(x)!=getfather(y)) puts("-1"); else write(get_min(x,y)),putchar('\n'); } return 0; }