1. 程式人生 > 實用技巧 >Luogu2680 運輸計劃

Luogu2680 運輸計劃

https://www.luogu.com.cn/problem/P2680

樹鏈剖分

我們對每條邊\(i\)單獨考慮,那麼設\(v_i\)為這條邊的長度,經過它的路徑長度集合為\(S\),未經過它的路徑長度集合為\(T\)

\[ans_i=\max \begin{cases} S_{max}-v_i \\ T_{max} \end{cases} \\ Ans=\min ans_i \]

對於\(S_{max}\),我們直接對於一條長度為\(L\)的路徑,該路徑上的邊都對\(L\)\(\max\),用樹鏈剖分很容易處理

對於\(T_{max}\),對於一條長度為\(L\)的路徑,不在該路徑上的邊都對\(L\)

\(\max\),也就是計算\(S_{max}\)時邊的補集,我們可以記錄樹剖時覆蓋了哪些段,剩餘的段就是\(T_{max}\)應當覆蓋的了,由於樹剖頂多\(\log n\)段,\(T_{max}\)覆蓋的段頂多比\(S_{max}\)覆蓋的段多一個

計算路徑長度\(L\),用了帶按秩合併優化的\(Tarjan\)\(LCA\)

時間複雜度:\(O(n \log^2 n)\)

掛點\(1.\)線段樹忘開四倍空間。。。

掛點\(2.\)一開始\(T\)了,結果發現是它的鍋

#define Rmin(x,y) ((x<y)?x:y)
#define Rmax(x,y) ((x>y)?x:y)

在下面的程式碼的線段樹中,由於\(define\),需要先線段樹搜尋一次,與\(y\)比較,然後返回值時再搜尋一次,時間爆炸

經驗:下次寫什麼函式之類的再也不用\(define\)\(QAQ\)

錯誤程式碼:

#define Rmin(x,y) ((x<y)?x:y)
#define Rmax(x,y) ((x>y)?x:y)
#define ls (p << 1)
#define rs ((p << 1) | 1)
#define lc ls,l,mid
#define rc rs,mid+1,r
struct Segment_Tree
{
    int tr[N];
    void modify(int p,int l,int r,int x,int y,int z)
    {
        if (l==x && r==y)
        {
            tr[p]=Rmax(tr[p],z);
            return;
        }
        int mid=(l+r) >> 1;
        if (y<=mid)
            modify(lc,x,y,z); else
        if (x>mid)   
            modify(rc,x,y,z); else
            {
                modify(lc,x,mid,z);
                modify(rc,mid+1,y,z);
            }
    }
    int query(int p,int l,int r,int x)
    {
        if (l==r)
            return tr[p];
        int mid=(l+r) >> 1;
        if (x<=mid)
            return Rmax(tr[p],query(lc,x)); else
            return Rmax(tr[p],query(rc,x));
    }
}t1,t2;

完整\(AC\)程式碼

\(Code:\)

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<vector>
#define N 300005
using namespace std;
int n,m,x,y,z,tot=0,fr[N],nxt[N << 1],d1[N << 1],d2[N << 1];
int cnt=0,f[N],dep[N],son[N],sz[N],dfn[N],t[N],len[N];
int ans,ft[N],rf[N],rz[N],rg[N],lca[N];
struct node
{
    int x,y;
    node (int xx=0,int yy=0)
    {
        x=xx,y=yy;
    }
    bool operator < (const node &b) const
    {
        return x<b.x;
    }
}q[N],g[N];
vector<node>e[N];
int read()
{
    int S=0;
    char c=getchar();
    while (c<'0' || c>'9')
        c=getchar();
    while ('0'<=c && c<='9')
    {
        S=S*10+c-'0';
        c=getchar();
    }
    return S;
}
void write(int x)
{
    if (x>9)
        write(x/10);
    putchar(x%10+'0');
}
void add(int x,int y,int z)
{
    tot++;
    d1[tot]=y;
    d2[tot]=z;
    nxt[tot]=fr[x];
    fr[x]=tot;
}
int getf(int x)
{
    return (x==rf[x])?x:(rf[x]=getf(rf[x]));
}
void dfs1(int u)
{
    rf[u]=u;
    rg[u]=u;
    rz[u]=1;
    int mx=0;
    sz[u]=1;
    for (int i=fr[u];i;i=nxt[i])
    {
        int v=d1[i];
        if (v==f[u])
            continue;
        f[v]=u;
        dep[v]=dep[u]+1;
        len[v]=len[u]+d2[i];
        ft[v]=d2[i];
        dfs1(v);
        sz[u]+=sz[v];
        if (sz[v]>mx)
        {
            mx=sz[v];
            son[u]=v;
        }
        int fu=getf(u);
        int fv=getf(v);
        if (rz[fv]<=rz[fu])
        {
            rz[fu]+=rz[fv];
            rf[fv]=fu;
        } else
        {
            rf[fu]=fv;
            rz[fv]+=rz[fu];
            rg[fv]=u;
        }
    }
    for (vector<node> :: iterator it=e[u].begin();it!=e[u].end();++it)
        if (rf[it->x])
            lca[it->y]=rg[getf(it->x)];
}
void dfs2(int u,int tt)
{
    dfn[u]=++cnt;
    t[u]=tt;
    if (!son[u])
        return;
    dfs2(son[u],tt);
    for (int i=fr[u];i;i=nxt[i])
    {
        int v=d1[i];
        if (v==f[u] || v==son[u])
            continue;
        dfs2(v,v);
    }
}
#define ls (p << 1)
#define rs ((p << 1) | 1)
#define lc ls,l,mid
#define rc rs,mid+1,r
struct Segment_Tree
{
    int tr[N << 2];
    void modify(int p,int l,int r,int x,int y,int z)
    {
        if (l==x && r==y)
        {
            tr[p]=max(tr[p],z);
            return;
        }
        int mid=(l+r) >> 1;
        if (y<=mid)
            modify(lc,x,y,z); else
        if (x>mid)   
            modify(rc,x,y,z); else
            {
                modify(lc,x,mid,z);
                modify(rc,mid+1,y,z);
            }
    }
    int query(int p,int l,int r,int x)
    {
        if (l==r)
            return tr[p];
        int mid=(l+r) >> 1;
        if (x<=mid)
            return max(tr[p],query(lc,x)); else
            return max(tr[p],query(rc,x));
    }
}t1,t2;
void Achange(int x,int y,int z)
{
    int g0=0;
    while (t[x]!=t[y])
    {
        if (dep[t[x]]<dep[t[y]])
            swap(x,y);
        t1.modify(1,1,n,dfn[t[x]],dfn[x],z);
        g[++g0]=node(dfn[t[x]],dfn[x]);
        x=f[t[x]];
    }
    if (x!=y)
    {
        if (dep[x]>dep[y])
            swap(x,y);
        t1.modify(1,1,n,dfn[son[x]],dfn[y],z);
        g[++g0]=node(dfn[son[x]],dfn[y]);
    }
    sort(g+1,g+g0+1);
    int o=1;
    for (int i=1;i<=g0;o=g[i].y+1,i++)
    {
        if (g[i].x==o)
            continue;
        t2.modify(1,1,n,o,g[i].x-1,z);
    }
    if (o<=n)
        t2.modify(1,1,n,o,n,z);
}
int main()
{
    n=read(),m=read();
    for (int i=1;i<n;i++)
    {
        x=read(),y=read(),z=read();
        add(x,y,z),add(y,x,z);
    }
    for (int i=1;i<=m;i++)
        q[i].x=read(),q[i].y=read(),e[q[i].x].push_back(node(q[i].y,i)),e[q[i].y].push_back(node(q[i].x,i));
    dfs1(1);
    dfs2(1,1);
    for (int i=1;i<=m;i++)
    {
        int x=q[i].x,y=q[i].y,z=lca[i];
        int l=len[x]+len[y]-(len[z] << 1);
        Achange(x,y,l);
    }
    ans=1000000007;
    for (int i=2;i<=n;i++)
    {
        int e=t1.query(1,1,n,dfn[i])-ft[i];
        int o=t2.query(1,1,n,dfn[i]);
        ans=min(ans,max(e,o));
    }
    write(ans),putchar('\n');
    return 0;
}