疫情控制

洛谷

其实在很久之前我就差不多大致理解思路

但由于过于蒟蒻

难以实现

在大约一月前我刷树形dp时,又刷到这道题

嗯,我用dp get到0pts的好成绩

反正我现在就是懂了

#include<bits/stdc++.h>
#define re return
#define ll long long
#define dec(i,l,r) for(register int i=l;i>=r;--i)
#define inc(i,l,r) for(register int i=l;i<=r;++i) 
using namespace std;
template<typename T>inline void rd(T&x)
{
    char c;bool f=0;
    while((c=getchar())<'0'||c>'9')if(c=='-')f=1;
    x=c^48;
    while((c=getchar())>='0'&&c<='9')x=x*10+(c^48);
    if(f)x=-x;
}

const int maxn=300005;
int cnt,k,n,m,hd[maxn],fa[maxn][21];
int size1,pos[maxn],vis[maxn];

long long dis[maxn][21];

struct node{
    int to,nt,val;
}e[maxn<<1];
inline void add(int x,int y,int z)
{
    e[++k].to=y;e[k].nt=hd[x];hd[x]=k;e[k].val=z;
    e[++k].to=x;e[k].nt=hd[y];hd[y]=k;e[k].val=z;
}


inline void dfs(int x)
{
    for(int i=0;fa[fa[x][i]][i];++i)
    {
        fa[x][i+1]=fa[fa[x][i]][i];
        dis[x][i+1]=dis[x][i]+dis[fa[x][i]][i];
    }
    
    for(int i=hd[x];i;i=e[i].nt)
    {
        int v=e[i].to;
        if(v==fa[x][0])continue;
        fa[v][0]=x;
        dis[v][0]=e[i].val;
        dfs(v);
    }
}

struct lll
{
    int fr,left_dis,id;
    bool operator<(lll c)const
    {
        re left_dis<c.left_dis;
    }
}a[maxn];

int cnta,cntb,need[maxn];
struct lli
{
    int val,id;
    bool operator<(lli c)const
    {
        re val<c.val;
    }
}b[maxn];

inline bool dfs1(int x)
{
    if(vis[x])re 1;
    int siz=0;
    for(int i=hd[x];i;i=e[i].nt)
    {
        int v=e[i].to;
        if(v==fa[x][0])continue;
        siz|=1;
        if(dfs1(v)==0)
        {vis[x]=0;re 0;}
    }
    if(!siz)
        {vis[x]=0;re 0;}
    vis[x]=1;
    re 1;
}

inline bool check(ll x)
{
    cntb=cnta=0;
    inc(i,0,n)vis[i]=0; 
    
    inc(i,1,m)
    {
        int v=pos[i],now=0;
        dec(i,20,0)if(fa[v][i]>1&&dis[v][i]+now<=x){now+=dis[v][i];v=fa[v][i];}
        
        int left=x-now-dis[v][0];
        
        if(fa[v][0]==1&&left>=0)
        //在边界点//能返回点或者已被注扎 
        //left是从1出发能走的最远距离 
            a[++cnta]=(lll){v,left,cnta};
        
        else vis[v]=1;
    }
    
    //将不能被封闭的点标记 
    for(int i=hd[1];i;i=e[i].nt)
    {
        int v=e[i].to;
        dfs1(v);
    }
    
    sort(a+1,a+cnta+1);
    int nowa=0;
    
    
    //找到最小的不能返回出发节点(未封闭)的值 
    inc(i,1,cnta)
    {
        if(!vis[a[i].fr]&&a[i].left_dis<dis[a[i].fr][0])
        {
            a[i].left_dis=-1;
            vis[a[i].fr]=1;
            --nowa;
        }
    }
    
    sort(a+1,a+cnta+1);
    for(int i=hd[1];i;i=e[i].nt)
    {
        int v=e[i].to;
        if(!vis[v])b[++cntb]=(lli){e[i].val,v};
    }
    sort(b+1,b+cntb+1);
    
    int nowb=1;
    inc(i,nowa+1,cnta)
    {
        if(b[nowb].val<=a[i].left_dis)++nowb;
        if(nowb==cntb+1)re 1;
    }
    
    re 0;
}
int main()
{
freopen("in.txt","r",stdin);
//    freopen("testdata.in","r",stdin);
    int x,y,z;    
    ll l=0,r=0;
    rd(n);
    inc(i,2,n)
    {
        rd(x),rd(y),rd(z);
        add(x,y,z);
        r+=z;
    }
    
    //dfs得到倍增数组 
    for(int i=hd[1];i;i=e[i].nt)
    {
        ++size1;
        int v=e[i].to;
        fa[v][0]=1;dis[v][0]=e[i].val;
        dfs(v);
    }    
    
    rd(m);
    if(m<size1){printf("-1");re 0;}
    
    inc(i,1,m)rd(pos[i]);

    while(l<=r)
    {
        int mid=(l+r)>>1;
        if(check(mid))r=mid-1;
        else l=mid+1;
    }
    
    printf("%lld",l);
    re 0;
} 
原文地址:https://www.cnblogs.com/lsyyy/p/11529933.html