如今開始正式填之前欠下的一些題解。就從這道經典的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; }