ccz181078

  博客园 :: 首页 :: 博问 :: 闪存 :: 新随笔 :: 联系 :: :: 管理 ::

http://uoj.ac/problem/11

树形dp求出每个点的到最远黑点的距离 和 这个点到所有最远黑点的路径的交 的另一端(lca也可以顺便记录),然后树上差分标记一下,统计出每个点被路径交覆盖了几次,由此可以计算答案。

#include<bits/stdc++.h>
char ib[10000007],*ip=ib;
int _(){
    int x=0;
    while(*ip<48)++ip;
    while(*ip>47)x=x*10+*ip++-48;
    return x;
}
typedef long long i64;
const int N=1e5+7;
const i64 inf=1ll<<60;
struct edge{
    int to,nx,v;
}e[N*2];
int n,m,e0[N],ep=2,ans=-1,at,fa[N],t[N];
bool is[N];
struct D1{
    i64 md;
    int w;
    void upd(const D1&d,int w0){
        if(d.md>md)*this=d;
        else if(d.md==md)w=w0;
    }
    D1 operator+(int x){
        return (D1){md+x,w};
    }
}v1[N],v2[N],D1_nul=(D1){-inf,0};
struct D2{
    i64 md;
    int w,lca;
    void upd(const D1&d,int w0){
        if(d.md>md)md=d.md,w=d.w,lca=w0;
        else if(d.md==md)w=lca=w0;
    }
    void ins(int w0){
        ++t[w0];
        ++t[w];
        --t[lca];
        --t[fa[lca]];
    }
}d2[N],D2_nul=(D2){-inf,0,0};
void f1(int w,int pa){
    fa[w]=pa;
    v1[w]=is[w]?(D1){0,w}:D1_nul;
    for(int i=e0[w];i;i=e[i].nx){
        int u=e[i].to;
        if(u==pa)continue;
        f1(u,w);
        v1[w].upd(v1[u]+e[i].v,w);
    }
}
int cs[N],cp=0;
void f2(int w){
    cp=0;
    for(int i=e0[w];i;i=e[i].nx){
        int u=e[i].to;
        if(u!=fa[w])cs[++cp]=i;
    }
    v2[cp+1]=D1_nul;
    for(int t=cp;t;--t){
        int i=cs[t],u=e[i].to;
        v2[t]=v2[t+1];
        v2[t].upd(v1[u]+e[i].v,w);
    }
    D1 v3=is[w]?(D1){0,w}:D1_nul;
    for(int t=1;t<=cp;++t){
        int i=cs[t],u=e[i].to;
        d2[u]=d2[w];
        d2[u].upd(v2[t+1],w);
        d2[u].upd(v3,w);
        d2[u].md+=e[i].v;
        v3.upd(v1[u]+e[i].v,w);
    }
    for(int i=e0[w],t=1;i;i=e[i].nx){
        int u=e[i].to;
        if(u!=fa[w])f2(u);
    }
    if(is[w]){
        d2[w].upd(v1[w],w);
        d2[w].ins(w);
    }
}
void f3(int w){
    for(int i=e0[w];i;i=e[i].nx){
        int u=e[i].to;
        if(u==fa[w])continue;
        f3(u);
        t[w]+=t[u];
    }
    if(!is[w]){
        if(t[w]>ans)ans=t[w],at=0;
        if(t[w]==ans)++at;
    }
}
int main(){
    fread(ib,1,sizeof(ib),stdin);
    n=_(),m=_();
    int rt=n;
    for(int i=1;i<=m;++i)is[_()]=1;
    for(int i=1,a,b,c;i<n;++i){
        a=_(),b=_(),c=_();
        e[ep]=(edge){b,e0[a],c};e0[a]=ep++;
        e[ep]=(edge){a,e0[b],c};e0[b]=ep++;
    }
    f1(rt,0);
    d2[rt]=is[rt]?(D2){0,rt,rt}:D2_nul;
    f2(rt);
    f3(rt);
    printf("%d %d\n",ans,at);
    return 0;
}

 

posted on 2017-09-11 13:55  nul  阅读(166)  评论(0编辑  收藏  举报