1. 程式人生 > >luogu P1084 疫情控制

luogu P1084 疫情控制

enable -- 節點和 using 時間排序 cmp printf fin tps

傳送門

首先,所有軍隊又要盡量往上走,這樣才能盡可能的封鎖更多的到葉子的路徑

而隨著時間的增加,能封鎖的路徑也就越來越多,所以可以二分最終的時間

然後對於每個時間,就讓能走到根的軍隊走到根,記錄到根上一個節點和剩余時間,然後按時間排序;不能走到的就在能走到的最上面的點打標記.然後遍歷樹一遍,把所有的兒子被打標記的點打標記;然後把根的沒打標記的兒子提出來,和之前到達根的軍隊一一匹配:把那些兒子按照到根的距離從大到小排序,對於每個兒子,考慮用退回上一個節點匹配,不行就用剩余時間足夠的匹配,都不行就用當前軍隊退回去匹配,然後考慮下一個軍隊

有點毒瘤似不似

註:保存到根的節點建議用\(multiset\)

,向下面代碼裏面寫的能過洛谷上的題,但是仍有問題懶得改了

// luogu-judger-enable-o2
#include<bits/stdc++.h>
#define LL long long
#define il inline
#define re register
#define inf 2099999999
#define max(a,b) ((a)>(b)?(a):(b))
#define min(a,b) ((a)<(b)?(a):(b))
#define db double
#define eps (1e-5)

using namespace std;
const int N=50000+10;
il LL rd()
{
    re LL x=0,w=1;re char ch=0;
    while(ch<'0'||ch>'9') {if(ch=='-') w=-1;ch=getchar();}
    while(ch>='0'&&ch<='9') {x=(x<<3)+(x<<1)+(ch^48);ch=getchar();}
    return x*w;
}
int to[N<<1],nt[N<<1],hd[N],tot=1;
LL w[N<<1];
il void add(int x,int y,LL z)
{
  ++tot,to[tot]=y,nt[tot]=hd[x],w[tot]=z,hd[x]=tot;
  ++tot,to[tot]=x,nt[tot]=hd[y],w[tot]=z,hd[y]=tot;
}
struct nnn
{
  LL x;int la;
  bool operator < (const nnn &a) const{return x>a.x;}
}st[N<<1];
int n,m,nn,a[N],fa[N][17],tt,tp,cn[N];
LL s[N][17],di[N],l,r,ans,so[N];
bool v[N];
il bool cmp(int a,int b){return di[a]>di[b];}
void dfs(int x)
{
  r=max(r,di[x]);
  for(int j=1;j<=nn;j++) fa[x][j]=fa[fa[x][j-1]][j-1],s[x][j]=(fa[x][j]>0)?(s[x][j-1]+s[fa[x][j-1]][j-1]):(1ll<<50);
  for(int i=hd[x];i;i=nt[i])
    {
      int y=to[i];
      if(y==fa[x][0]) continue;
      fa[y][0]=x,s[y][0]=w[i],di[y]=di[x]+w[i];
      dfs(y);
    }
}
void dd(int x)
{
  if(v[x]) return;
  v[x]=true;
  int cnt=0;
  for(int i=hd[x];i;i=nt[i])
    {
      int y=to[i];
      if(y==fa[x][0]) continue;
      dd(y);
      v[x]&=v[y];
      ++cnt;
    }
  if(!cnt) v[x]=false;
}
il bool check(LL ti)
{
  memset(v,0,sizeof(v));
  memset(cn,0,sizeof(cn));
  tt=tp=0;
  for(int i=1;i<=m;i++)
    {
      if(di[a[i]]<ti)
        {
          int nw=a[i];
          for(int j=nn;j>=0;j--) if(fa[nw][j]>1) nw=fa[nw][j];
          st[++tt]=(nnn){ti-di[a[i]],nw},++cn[nw];
          continue;
        }
      int nw=a[i];LL ss=0;
      for(int j=nn;j>=0;j--) if(ss+s[nw][j]<=ti&&fa[nw][j]>1) ss+=s[nw][j],nw=fa[nw][j];
      if(nw>1) v[nw]=true;
    }
  sort(st+1,st+tt+1);
  dd(1);
  for(int i=hd[1];i;i=nt[i])
    if(!v[to[i]]) so[++tp]=to[i];
  sort(so+1,so+tp+1,cmp);
  int j=1;
  for(int i=1;i<=tt&&j<=tp;i++)
    {
      if(cn[so[j]]>0) --cn[so[j]],--i,v[so[j]]=true;
      else if(st[i].x>=di[so[j]]&&cn[st[i].la]>0) --cn[st[i].la],v[so[j]]=true;
      else if(cn[st[i].la]>0) --cn[st[i].la],st[++tt]=(nnn){st[i].x,st[i].la},v[st[i].la]=true;
      while(j<=tp&&v[so[j]]==true) ++j;
    }
   return j>tp;
}

int main()
{
  n=rd(),nn=log(n)/log(2)+1;
  for(int i=1;i<n;i++)
    {
      int x=rd(),y=rd(),z=rd();
      add(x,y,z);
    }
  dfs(1);
  m=rd();
  for(int i=1;i<=m;i++) a[i]=rd();
  l=0,r<<=1ll,ans=1ll<<60;
  while(l<=r)
    {
      LL mid=(l+r)>>1;
      if(check(mid)) r=mid-1,ans=mid;
      else l=mid+1;
    }
  printf("%lld\n",ans<(1ll<<60)?ans:-1);
  return 0;
}

luogu P1084 疫情控制