[NOIP2015]运输计划

链接

luogu
好久没写博客了,水一篇波。

思路1 暴力数据结构

枚举最长链的边,删除后代价为(最长链-边权,不经过这条边的链)的最大值。
不经过某条边的最大值要用线段树维护补集。
复杂度\(O(nlog^2n)\)

思路2 二分树上差分

二分答案,删除的边为\(>mid\)的链的交集。
用树上查分维护交集。
最后在交集中找个最大的边删除就好了。
复杂度\(O(nlogn)\)

总的

思路2,复杂度小,好写,简单,细节少。
思路1,复杂度高,码量大,细节多,并不是呢么好想。
所以并不是很建议写第一种。
但他靠着树剖的小常数跑过了树上差分(至少我是这样,1.9s->1.2s)。

代码1

#include <bits/stdc++.h>
using namespace std;
const int _=5e5+7;
int read() {
    int x=0,f=1;char s=getchar();
    for(;s>'9'||s<'0';s=getchar()) if(s=='-') f=-1;
    for(;s>='0'&&s<='9';s=getchar()) x=x*10+s-'0';
    return x*f;
}
int n,m,ans,u[_],v[_],dsr[_],w[_];
struct node {
    int v,nxt,q,w;
}e[_<<1];
int head[_],tot;
void add(int u,int v,int q) {
    e[++tot].v=v;
    e[tot].q=q;
    e[tot].nxt=head[u];
    head[u]=tot;
}
int f[_],dep[_],siz[_],son[_],top[_],idx[_],dis[_],nb[_],cnt;
void dfs1(int u,int fa) {
    dep[u]=dep[fa]+1;
    f[u]=fa;
    siz[u]=1;
    for(int i=head[u];i;i=e[i].nxt) {
        int v=e[i].v;
        if(v==fa) continue;
        w[v]=e[i].q;
        dis[v]=dis[u]+e[i].q;
        dfs1(v,u);
        siz[u]+=siz[v];
        if(siz[son[u]]<siz[v]) son[u]=v;
    }
}
void dfs2(int u,int topf) {
    top[u]=topf;
    idx[u]=++cnt;
    nb[cnt]=u;
    if(!son[u]) return;
    dfs2(son[u],topf);
    for(int i=head[u];i;i=e[i].nxt) {
        int v=e[i].v;
        if(!idx[v]) dfs2(v,v);
    }
}
namespace seg_tree {
    #define ls rt<<1
    #define rs rt<<1|1
    int ma[_<<2],lazy[_];
    void tag(int rt,int val) {ma[rt]=max(ma[rt],val);lazy[rt]=max(lazy[rt],val);}
    void pushdown(int rt) {tag(ls,lazy[rt]);tag(rs,lazy[rt]);}
    void modify(int L,int R,int val,int l,int r,int rt) {
        if(L>R) return;
        if(L<=l&&r<=R) return tag(rt,val);
        int mid=(l+r)>>1;
        pushdown(rt);
        if(L<=mid) modify(L,R,val,l,mid,ls);
        if(R>mid) modify(L,R,val,mid+1,r,rs);
        ma[rt]=max(ma[ls],ma[rs]);
    }
    void dfs(int l,int r,int rt) {
        if(l==r) return void(dsr[nb[l]]=ma[rt]);
        int mid=(l+r)>>1;
        pushdown(rt);
        if(l<=mid) dfs(l,mid,ls);
        if(r>mid) dfs(mid+1,r,rs);
    }
}
int lca(int x,int y) {
    while(top[x]!=top[y]) {
        if(dep[top[x]]<dep[top[y]]) swap(x,y);
        x=f[top[x]];
    } return dep[x]<dep[y]?x:y;
}
void QQ(int x,int y,int val) {
    int las=n;
    while(top[x]!=top[y]) {
        if(dep[top[x]]<dep[top[y]]) swap(x,y);
        seg_tree::modify(idx[x]+1,las,val,1,n,1);
        las=idx[top[x]]-1;
        x=f[top[x]];
    }
    if(dep[x]<dep[y]) swap(x,y);
    seg_tree::modify(idx[x]+1,las,val,1,n,1);
    seg_tree::modify(1,idx[y],val,1,n,1);
}
int main() {
    n=read(),m=read();
    for(int i=1,x,y,q;i<n;++i) {
        x=read(),y=read(),q=read();
        add(x,y,q),add(y,x,q);
    }
    for(int i=1;i<=m;++i) {
        u[i]=read(),v[i]=read();
        if(u[i]==v[i]) m--,i--;
    }
    dfs1(1,0),dfs2(1,1);
    int id=0,ma=0;
    for(int i=1;i<=m;++i) {
        int val=dis[u[i]]+dis[v[i]]-2*dis[lca(u[i],v[i])];
        QQ(u[i],v[i],val);
        if(ma<val) id=i,ma=val;
    }
    if(!id) return printf("0\n"),0;
    seg_tree::dfs(1,n,1);
    int x=u[id],y=v[id],ans=0x3f3f3f3f;
    while(x!=y) {
        if(dep[x]<dep[y]) swap(x,y);
        ans=min(ans,max(dsr[x],ma-w[x]));
        x=f[x];
    }
    cout<<ans<<"\n";
    return 0;
}

代码2

#include <bits/stdc++.h>
using namespace std;
const int _=5e5+7;
int read() {
    int x=0,f=1;char s=getchar();
    for(;s>'9'||s<'0';s=getchar()) if(s=='-') f=-1;
    for(;s>='0'&&s<='9';s=getchar()) x=x*10+s-'0';
    return x*f;
}
int n,m,ans,u[_],v[_],LCA[_],len[_],the_biggest,w[_];
struct node {
    int v,nxt,q;
}e[_<<1];
int head[_],tot;
void add(int u,int v,int q) {
    e[++tot].v=v;
    e[tot].q=q;
    e[tot].nxt=head[u];
    head[u]=tot;
}
int f[_],dep[_],siz[_],son[_],dis[_],top[_],cnt;
void dfs1(int u,int fa) {
    dep[u]=dep[fa]+1,f[u]=fa,siz[u]=1;
    for(int i=head[u];i;i=e[i].nxt) {
        int v=e[i].v;
        if(v==fa) continue;
        w[v]=e[i].q;
        dis[v]=dis[u]+e[i].q;
        dfs1(v,u);
        siz[u]+=siz[v];
        if(siz[son[u]]<siz[v]) son[u]=v;
    }
}
void dfs2(int u,int topf) {
    top[u]=topf;
    if(!son[u]) return;
    dfs2(son[u],topf);
    for(int i=head[u];i;i=e[i].nxt) {
        int v=e[i].v;
        if(!top[v]) dfs2(v,v);
    }
}
int lca(int x,int y) {
    while(top[x]!=top[y]) {
        if(dep[top[x]]<dep[top[y]]) swap(x,y);
        x=f[top[x]];
    } return dep[x]<dep[y]?x:y;
}
int dsr[_],js;
void dfs(int u,int fa) {
    for(int i=head[u];i;i=e[i].nxt) {
        int v=e[i].v;
        if(v==fa) continue;
        dfs(v,u);
        dsr[u]+=dsr[v];
    }
}
bool check(int mid) {
    js=0;
    for(int i=0;i<=n;++i) dsr[i]=0;
    for(int i=1;i<=m;++i) {
        if(len[i]<=mid) continue;
        dsr[LCA[i]]-=2;
        dsr[u[i]]++;
        dsr[v[i]]++;
        ++js;
    }
    dfs(1,0);
    int ma=0x3f3f3f3f;
    for(int i=1;i<=n;++i)
        if(dsr[i]==js) ma=min(ma,the_biggest-w[i]);
    return ma<=mid;
}
int main() {
    n=read(),m=read();
    for(int i=1,x,y,q;i<n;++i) {
        x=read(),y=read(),q=read();
        add(x,y,q),add(y,x,q);
    }
    dfs1(1,0),dfs2(1,1);
    for(int i=1;i<=m;++i) {
        u[i]=read(),v[i]=read(),LCA[i]=lca(u[i],v[i]);
        len[i]=dis[u[i]]+dis[v[i]]-2*dis[LCA[i]];
        the_biggest=max(the_biggest,len[i]);
    }
    int l=0,r=the_biggest,ans=0;
    while(l<=r) {
        int mid=(l+r)>>1;
        if(check(mid)) ans=mid,r=mid-1;
        else l=mid+1;
    } cout<<ans<<"\n";
    return 0;
}
01-19 21:12