Luogu P1967 貨車運輸

如今開始正式填之前欠下的一些題解。就從這道經典的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;
}
相關文章
相關標籤/搜索