LGP4886 快递员

Posted asuldb

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了LGP4886 快递员相关的知识,希望对你有一定的参考价值。

题目

好秒啊,真是一道神仙的点分治

于是我们来一个暴力的\(O(nlog^2n)\)的暴力统计吧

考虑计算每一个点作为快递中心时的答案

我们考虑在这个点成为分治重心时计算这个贡献

把这个贡献分成两部分

  1. 分治块内部的点对,且不跨过分治重心,这个我们直接暴力统计就好了

  2. 分治块外部,这个又分成两种,一种是跨过分治重心的路径,显然这样的点对的贡献就是路径长度;一种是两个点都在分治块外部

都在分治块外部的话好像很难去计算了,但是我们考虑尽管对于当前的分治重心都在分治块外部,但是对于这个点在点分树上的祖先,这种点对必然在某一个祖先的分治块内部,而且是在同一棵子树里的那种

于是我们对于每一个点暴力访问其在点分树上的祖先,算一下两点之间的距离

由于只需要计算最大的贡献,我们对于每一点都只保留最大的来自于同一子树的点对贡献

但是这样还是不科学,因为我们递归进这个子树的时候,最大值也可能来自这个子树,所以我们还需要保留次大值,就是为了在处理贡献最大子树的时候不出错

显然点分树的树高是\(logn\)的,但是我们需要计算树上距离需要一个链剖求\(lca\),复杂度是\(O(nlog^2n)\)

代码

#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdio>
#include<vector> 
#define re register
#define LL long long
#define max(a,b) ((a)>(b)?(a):(b))
#define min(a,b) ((a)<(b)?(a):(b))
const int maxn=1e5+5;
const int inf=1e9;
inline int read() {
    char c=getchar();int x=0;while(c<'0'||c>'9') c=getchar();
    while(c>='0'&&c<='9') x=(x<<3)+(x<<1)+c-48,c=getchar();return x;
}
struct E{int v,nxt,w;}e[maxn<<1];
int vis[maxn],head[maxn],sum[maxn],top[maxn],son[maxn],fa[maxn],pre[maxn];
int d[maxn],Fa[maxn],h[maxn],mx[maxn],deep[maxn],col[maxn];
int S,now,rt,n,num,tmp,g,ans,m,ml;
int r[maxn<<1],len[maxn<<1];
std::vector<int> v[maxn],tp[maxn];
inline void add(int x,int y,int w) {
    e[++num].v=y;e[num].nxt=head[x];
    head[x]=num;e[num].w=w;
}
void getroot(int x,int fa) {
    sum[x]=1,mx[x]=0;
    for(re int i=head[x];i;i=e[i].nxt) {
        if(vis[e[i].v]||e[i].v==fa) continue;
        getroot(e[i].v,x);sum[x]+=sum[e[i].v];
        mx[x]=max(mx[x],sum[e[i].v]);
    }
    mx[x]=max(mx[x],S-sum[x]);
    if(mx[x]<now) now=mx[x],rt=x;
}
void dfs1(int x) {
    sum[x]=1;int maxx=-1;
    for(re int i=head[x];i;i=e[i].nxt) {
        if(deep[e[i].v]) continue;
        deep[e[i].v]=deep[x]+1;fa[e[i].v]=x;
        pre[e[i].v]=pre[x]+e[i].w;
        dfs1(e[i].v);sum[x]+=sum[e[i].v];
        if(sum[e[i].v]>maxx) maxx=sum[e[i].v],son[x]=e[i].v;
    }
}
void dfs2(int x,int topf) {
    top[x]=topf;
    if(!son[x]) return;
    dfs2(son[x],topf);
    for(re int i=head[x];i;i=e[i].nxt)
    if(!top[e[i].v]) dfs2(e[i].v,e[i].v);
}
inline int LCA(int x,int y) {
    while(top[x]!=top[y]) {
        if(deep[top[x]]<deep[top[y]]) std::swap(x,y);
        x=fa[top[x]];
    }
    if(deep[x]<deep[y]) return x;return y;
}
inline int dis(int x,int y) {return pre[x]+pre[y]-2*pre[LCA(x,y)];}
void getro(int x,int fa,int c) {
    col[x]=c;
    for(re int j=0;j<v[x].size();j++) {
        int t=v[x][j];
        if(col[r[t^1]]==c) tmp=max(tmp,d[x]+d[r[t^1]]);
    }
    for(re int i=head[x];i;i=e[i].nxt) {
        if(vis[e[i].v]||e[i].v==fa) continue;
        d[e[i].v]=d[x]+e[i].w;
        getro(e[i].v,x,c);
    }
}
void Dfs(int x,int fa) {
    for(re int i=head[x];i;i=e[i].nxt) {
        if(vis[e[i].v]||e[i].v==fa) continue;
        Dfs(e[i].v,x);
    }
    col[x]=0;
}
void dfs(int x) {
    vis[x]=1;int cnt=0,m1=0,m2=0;
    g=ml;d[x]=0;
    for(re int i=head[x];i;i=e[i].nxt) {
        if(vis[e[i].v]) continue;
        col[x]=++cnt;tmp=0;d[e[i].v]=e[i].w;
        getro(e[i].v,0,cnt);
        tp[x].push_back(tmp);
        if(tmp>m1) m2=m1,m1=tmp;
            else m2=max(m2,tmp);
    }
    Dfs(x,0);int y=x;
    while(Fa[y]) {
        y=Fa[y];
        int mid=2*dis(x,y)+h[y];
        if(h[y]) g=max(g,mid);
    }
    g=max(g,m1);ans=min(ans,g);
    for(re int j=0,i=head[x];i;i=e[i].nxt,j++) {
        if(vis[e[i].v]) continue;
        S=sum[e[i].v],now=inf,getroot(e[i].v,0);
        if(tp[x][j]==m1) h[x]=m2;
            else h[x]=m1;
        Fa[rt]=x;dfs(rt);
    }
}
int main() {
    n=read(),m=read();ans=inf;
    for(re int x,y,z,i=1;i<n;i++)
        x=read(),y=read(),z=read(),add(x,y,z),add(y,x,z);
    deep[1]=1,dfs1(1),dfs2(1,1);
    int tot=1;
    for(re int i=1;i<=m;i++) {
        r[++tot]=read();
        v[r[tot]].push_back(tot);
        r[++tot]=read();
        v[r[tot]].push_back(tot);
        len[tot]=len[tot-1]=dis(r[tot],r[tot-1]);
        ml=max(ml,len[tot]);
    }
    S=n,now=inf,getroot(1,0);
    dfs(rt);
    printf("%d\n",ans);
    return 0;
}

以上是关于LGP4886 快递员的主要内容,如果未能解决你的问题,请参考以下文章

[题解]luogu_P4886_快递员(点分治

luogub P4886 快递员(点分治)

定区关联快递员 定区关联收派时间

快递员依据管理中心发来收件信息

作业五

快递员外卖员权益保障政策出台,网约车及货车司机保障亟待被关注