萌新求助 悬赏关注 WA #2 #8
查看原帖
萌新求助 悬赏关注 WA #2 #8
167875
137QWQ楼主2022/10/13 14:26

传送门

#include<bits/stdc++.h>
#define ll long long
using namespace std;
const int N=2e5+500;
int n,m,head[N],cnt=0;
int s[N],d[N],f[N][20],h[N];
ll l[N],mx[N],p[N],q[N],dp[N];
int bnt=0,pnt=0,qnt=0;
struct node
{
    ll t,now;
}b[N];
struct edge
{
    int to,next,w;
}e[N<<1];
void add(int u,int v,int w)
{
    e[++cnt].to=v;
    e[cnt].w=w;
    e[cnt].next=head[u];
    head[u]=cnt;
}
void dfs(int u,int fa) //预处理
{
    f[u][0]=fa;
    d[u]=d[fa]+1;
    for(int i=1;i<20;++i)
        for(int j=1;j+(1<<i)-1<=d[u];++j)
            f[u][i]=f[f[u][i-1]][i-1];
    for(int i=head[u];i;i=e[i].next)
    {
        int v=e[i].to;
        if(v==fa)continue;
        l[v]=l[u]+e[i].w;
        dfs(v,u);
    }
}
inline int log2(int x)
{
    if(x==1) return 0;
    if(!dp[x]) dp[x]=log2(x>>1)+1;
    return dp[x];
}
inline int lca(int u,int v)
{
    if(d[u]<d[v])swap(u,v);
    while(d[u]>d[v])
        u=f[u][log2(d[u]-d[v])];
    if(u==v) return u;
    for(int i=19;i>=0;--i)
    {
        if(f[u][i]!=f[v][i])
            u=f[u][i],v=f[v][i];
    }
    return f[u][0];
}
inline ll road(int u,int v)// u v之间路程
{
    return (l[u]+l[v]-2*l[lca(u,v)]);
}
inline ll road2(int u,int v)
{
    if(d[u]>d[v])swap(u,v);
    return (l[v]-l[u]);
}
bool dfs2(int u,int fa) //判断从u到u的所有叶子节点的路程上是否有军队驻扎 (即疫情是否可以被控制)
{
    if(h[u])return true;
    bool ans=head[e[head[u]].next];
    for(int i=head[u];i;i=e[i].next)
    {
        int v=e[i].to;
        if(v==fa)continue;
        ans&=dfs2(v,u);
    }
    return ans;
}
bool ask(ll t) //判断在t时间内是否可以控制疫情
{
    bnt=0; pnt=0; qnt=0;
    memset(mx,0,sizeof(mx));
    memset(h,0,sizeof(h));
    ll u,tn,v,w; b[0].t=1e18;
    for(int i=1;i<=m;++i)
    {
        u=s[i]; tn=t; b[0].t=1e18;
        for(int i=19;i>=0;--i)
            if(d[u]-(1<<i)>=2&&road(u,f[u][i])<=tn)
                tn-=road(u,f[u][i]),u=f[u][i];
        b[++bnt].t=tn; b[bnt].now=u; ++h[u]; // 尽可能的往上走
        if(d[u]==2) //到达离首都最近的节点 如果该节点有2支军队驻扎 剩余时间多的上去
        {
            v=mx[u];
            if(tn<b[v].t)
                mx[u]=bnt;
            else v=bnt;
            if(v==0)continue;
            b[v].t-=road(b[v].now,f[1][0]);
            --h[b[v].now]; ++h[1]; b[v].now=1;
            if(b[v].t>0) p[++pnt]=b[v].t;
        }
    }
    for(int i=head[1];i;i=e[i].next)
    {
        v=e[i].to; w=e[i].w;
        if(v==0)continue;
        if(h[v])
        {
            h[v]=0;
            if(dfs2(v,1)&&mx[v]!=0) //该节点有军队驻扎且去除该节点军队后仍能控制疫情
            {
                v=mx[v]; //这支军队上去
                b[v].t-=road(b[v].now,f[1][0]);
                --h[b[v].now]; ++h[1]; b[v].now=1;
                if(b[v].t>0) p[++pnt]=b[v].t;
            }
        }
        else if(!dfs2(v,1)) //该节点不能控制
            q[++qnt]=w;
    }
    /*for(int i=1;i<=pnt;++i)
        cout<<p[i]<<" ";
    cout<<t<<" "<<qnt<<endl;*/
    sort(p+1,p+pnt+1);
    sort(q+1,q+qnt+1);
    if(pnt<qnt)return false;
    int l=1;
    for(int r=1;r<=qnt;++r)//让在首都的军队到疫情无法控制的地方
    {
        while(p[l]<q[r]&&l<=pnt)
            ++l;
        if(l>pnt) return false; ++l;
    }
    return true;
}
int main()
{
    int u,v,w;
    cin>>n;
    for(int i=1;i<n;++i)
        cin>>u>>v>>w,add(u,v,w),add(v,u,w);
    cin>>m;
    for(int i=1;i<=m;++i)
        cin>>s[i];
    dfs(1,0);
    ll l=0,r=1e18,mid;
    while(l<r)
    {
        mid=(l+r)>>1;
        if(ask(mid))
            r=mid;
        else l=mid+1;
    }
    cout<<(l>1e17?-1:l)<<endl;
}

qwq 求捞

2022/10/13 14:26
加载中...