luogu1084 [NOIp2012]疫情控制 (二分答案+倍增+dfs序)

先二分出一个时间,把每个军队倍增往上跳到不能再跳

然后如果它能到1号点,就记下来它跳到1号点后剩余的时间;如果不能,就让它就地扎根,记一记它覆盖了哪些叶节点(我在这里用了dfs序+差分,其实直接dfs就行..)

然后对于那些叶节点没有被覆盖完全的(父亲为1号点的)子树,肯定需要一些已经到1号点的军队来走过去

如果它离1距离越远,肯定就希望用剩余时间越多的军队来走,除非是有一个剩余时间更少的军队本来就在这个子树里

看一看能不能符合要求的就行了

然而有很多要注意的地方:

0.一个军队只能用一次......(开始读错题 还在想为什么会有-1的情况)

1.只需要覆盖叶节点就行了,也就是说,统计这个子树有没有完全被覆盖的时候,不能统计到非叶节点

2.即使有军队本来在这个子树里,我也有可能不选这个军队来到这个子树里,因为它的剩余时间可能非常大

3.有可能到1号点的军队数不足覆盖掉那些没被覆盖的子树,这时候也是-1

4.每次judge要清零...

  1 #include<bits/stdc++.h>
  2 #define pa pair<int,int>
  3 #define CLR(a,x) memset(a,x,sizeof(a))
  4 using namespace std;
  5 typedef long long ll;
  6 const int maxn=5e4+10;
  7 
  8 inline ll rd(){
  9     ll x=0;char c=getchar();int neg=1;
 10     while(c<'0'||c>'9'){if(c=='-') neg=-1;c=getchar();}
 11     while(c>='0'&&c<='9') x=x*10+c-'0',c=getchar();
 12     return x*neg;
 13 }
 14 
 15 struct Edge{
 16     int b,ne;ll l;
 17 }eg[maxn*2];
 18 int egh[maxn],ect;
 19 int N,M,p[maxn];
 20 int dfn[maxn][2],tot,fa[maxn][20];
 21 int bel[maxn],cnt[maxn],tmp[maxn],tmp2[maxn];
 22 int mim[maxn],id[maxn];
 23 bool flag[maxn],islef[maxn];
 24 ll dis[maxn][20],rest[maxn];
 25 
 26 inline void adeg(int a,int b,ll l){
 27     eg[++ect].b=b;eg[ect].l=l;eg[ect].ne=egh[a];egh[a]=ect;
 28 }
 29 
 30 void dfs(int x){
 31     dfn[x][0]=++tot;id[tot]=x;
 32     for(int i=0;fa[x][i]&&fa[fa[x][i]][i];i++){
 33         fa[x][i+1]=fa[fa[x][i]][i];
 34         dis[x][i+1]=dis[x][i]+dis[fa[x][i]][i];
 35     }islef[x]=1;
 36     for(int i=egh[x];i;i=eg[i].ne){
 37         int b=eg[i].b;
 38         if(b==fa[x][0]) continue;
 39         fa[b][0]=x;dis[b][0]=eg[i].l;
 40         if(x==1) bel[b]=b;
 41         else bel[b]=bel[x];
 42         dfs(b);
 43         islef[x]=0;
 44     }
 45     dfn[x][1]=tot;
 46 }
 47 
 48 int getfe(int x,ll &lim){
 49     for(int i=17;i>=0;i--){
 50         if(fa[x][i]&&dis[x][i]<=lim) lim-=dis[x][i],x=fa[x][i];
 51     }
 52     return x;
 53 }
 54 
 55 inline bool cmp(int a,int b){return rest[a]>rest[b];}
 56 inline bool cmp2(int a,int b){return dis[a][0]>dis[b][0];}
 57 
 58 inline bool judge(ll m){
 59     // printf("!!%lld:
",m);
 60     int n,i,j;
 61     CLR(cnt,0);
 62     for(i=1,j=0;i<=M;i++){
 63         rest[i]=m;
 64         int x=getfe(p[i],rest[i]);
 65         // printf("%d %d %lld
",p[i],x,rest[i]);
 66         if(x==1) tmp[++j]=i;
 67         else{
 68             cnt[dfn[x][0]]++;
 69             cnt[dfn[x][1]+1]--;
 70         }
 71     }
 72     n=j;sort(tmp+1,tmp+n+1,cmp);
 73     CLR(flag,1);
 74     for(i=2,j=0;i<=N;i++){
 75         j+=cnt[i];
 76         if(j==0&&islef[id[i]]) flag[bel[id[i]]]=0;
 77     }
 78     CLR(mim,0);
 79     for(i=n;i;i--){
 80         if((!flag[bel[p[tmp[i]]]])&&(!mim[bel[p[tmp[i]]]])){
 81             mim[bel[p[tmp[i]]]]=i;
 82         }
 83     }
 84     for(i=2,j=0;i<=N;i++){
 85         if(fa[i][0]!=1||flag[i]) continue;
 86         tmp2[++j]=i;
 87     }m=j;
 88     sort(tmp2+1,tmp2+m+1,cmp2);
 89     if(n<m) return 0;
 90     for(i=1,j=1;i<=n&&j<=m;i++){
 91         if(!tmp[i]) continue;
 92         if(tmp[mim[tmp2[j]]]){
 93             tmp[mim[tmp2[j]]]=0;
 94             i--;
 95         }else{
 96             if(rest[tmp[i]]<dis[tmp2[j]][0]) return 0;
 97             tmp[i]=0;
 98         }j++;
 99     }
100     return j>m;
101 }
102 
103 int main(){
104     // freopen("testdata (1).in","r",stdin);
105     int i,j,k;
106     N=rd();
107     for(i=1;i<N;i++){
108         int a=rd(),b=rd(),c=rd();
109         adeg(a,b,c);adeg(b,a,c);
110     }dfs(1);
111     M=rd();
112     for(i=1;i<=M;i++) p[i]=rd();
113     ll l=0,r=1e15,ans=1e15+1;
114     while(l<=r){
115         ll m=l+r>>1;
116         if(judge(m)) ans=m,r=m-1;
117         else l=m+1;
118     }
119     if(ans==1e15+1) printf("-1
");
120     else printf("%lld
",ans);
121     return 0;
122 }
原文地址:https://www.cnblogs.com/Ressed/p/9735581.html