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;
}
posted @ 2020-09-11 16:30  GK0328  阅读(231)  评论(0编辑  收藏  举报