NOIP2012 D2 T3 疫情控制 洛谷P1084

题目链接:https://www.luogu.org/problemnew/show/P1084

算法:倍增,二分答案,贪心 + 瞎搞。。

背景:上学长的数论课啥也听不懂,于是前去提高组找安慰。不巧碰上了这个题。。蒟蒻整整码了一天。。。调了又一天。。。。最后看的洛谷@beretty的题解。。。。。过了。。。。。。

感谢@beretty。

 警告!:代码量3K左右。


思路:

大概分析:

  首先,我们需要知道怎样才能控制疫情。(废话。。 )

  通过题意,可以想到在一棵根节点的子树中,越靠近根节点的节点能控制该棵树的叶子节点(边境城市)的个数越多。

(比如在 4 这个节点,可以控制 15 7 11 3 12 2 这几个叶子节点)

  ?? 这说明了什么 ??

  通过思考,我们知道如果样例合法,最坏情况也就是将检查站全部设在根节点的儿子上,便能控制疫情。

为何是二分答案?

  再来分析一下问题:军队可以同时移动,说明我们的答案是移动时间最长的军队的移动时间。而我们要求最小值,即最大化最小值。

  !!!最大化最小值!!!

  典型的二分答案的标志。      二分什么? 当然是时间。

如何check?

  上文中提到了(!敲黑板)  越接近根节点的节点控制能力越强。 这说明,我们只需要在规定时间内贪心的把军队向根节点移动,移动的越远越好(不到根节点都可以)。

  如何移动? 当然不能暴力的一个一个往上移。这时候 倍增 这种东西就特别好用。我们可以先预处理出来每个节点向上跳$2^j$步是谁,顺便处理出到这个点的距离。

  之前的预处理代码:(大佬们请跳过。。)

 1 void dfs(int p,int f)
 2 {
 3     for(int i=head[p];i;i=nex[i])
 4     {
 5         int v=to[i];
 6         if(v!=f)
 7         {
 8             fa[v][0]=p;
 9             F[v][0]=val[i];
10             dfs(v,p);
11         }
12     }
13 }
View Code

  倍增预处理代码:

1 void update()
2 {
3     for(int j=1;j<=18;j++)
4         for(int i=1;i<=n;i++)
5         {
6             fa[i][j]=fa[fa[i][j-1]][j-1];
7             F[i][j]=F[i][j-1]+F[fa[i][j-1]][j-1];
8         }
9 }
View Code

    我们可以让规定时间内能到根节点的部队先全部到根节点,顺便记录它在向上跳的路径中根节点的儿子 $top$ ,以及到根节点时的剩余时间 $rest$。不能到根节点的部队到它能到的地方,打上标记。

  重点!!! 有时候我们会发现,有的子树上没有军队(该子树暂时不能被控制),这时候就需要跨子树(越过根节点)移动部队。!!!这里好难想 可以将所有到根节点的部队按照 $rest$ 从小到大排序,然后看看它在 $rest$ 时间内能不能回到 $top$ ,如果不能,就不让它在根节点呆着,让它移动到 $top$ 去,控制该子树。

  操作完毕后,我们将那些没被控制的子树的 $top$ 存好,从大到小排序。再将现在仍在根节点的部队从大到小排个序,看看能否将没被控制的的全部控制。能,返回true,否则返回false。

  以下为全部代码:

  1 #include <stdio.h>
  2 #include <algorithm>
  3 #include <string.h>
  4 using namespace std;
  5 const int N = 50005;
  6 const int root=1;
  7 const int logn = 19;
  8 int head[N];
  9 int to[N<<1];
 10 int nex[N<<1];
 11 int val[N<<1];
 12 int cnt,n,m;
 13 int fa[N][logn+1];
 14 int top[N];
 15 int tdis[N];
 16 int army[N];
 17 long long F[N][logn+1];
 18 bool pos[N];
 19 int q[N];
 20 bool vis[N];
 21 int cnt_a;
 22 void addedge(int a, int b,int v)
 23 {
 24     nex[++cnt]=head[a];
 25     head[a]=cnt;
 26     to[cnt]=b;
 27     val[cnt]=v;
 28 }
 29 void dfs(int p,int f)
 30 {
 31     for(int i=head[p];i;i=nex[i])
 32     {
 33         int v=to[i];
 34         if(v!=f)
 35         {
 36             fa[v][0]=p;
 37             F[v][0]=val[i];
 38             dfs(v,p);
 39         }
 40     }
 41 }
 42 void update()
 43 {
 44     for(int j=1;j<=18;j++)
 45         for(int i=1;i<=n;i++)
 46         {
 47             fa[i][j]=fa[fa[i][j-1]][j-1];
 48             F[i][j]=F[i][j-1]+F[fa[i][j-1]][j-1];
 49         }
 50 }
 51 void dfs1(int p,int f,int topf,int dist)
 52 {
 53     top[p]=topf;
 54     tdis[p]=dist;
 55     bool ft=0;
 56     for(int i=head[p];i;i=nex[i])
 57     {
 58         int v=to[i];
 59         if(v!=f)
 60         {
 61             ft=1;
 62             dfs1(v,p,topf,dist);
 63         }
 64     }
 65     if(!ft)
 66         pos[p]=1;
 67 }
 68 bool fs;
 69 void dfs2(int p,int f)
 70 {
 71     if(pos[p])
 72     {
 73         fs=1;
 74         return ;
 75     }
 76     for(int i=head[p];i;i=nex[i])
 77     {
 78         int v=to[i];
 79         if(v!=f&&!vis[v])
 80         {
 81             dfs2(v,p);
 82             if(fs)
 83                 return ;
 84         }
 85     }
 86 }
 87 bool check2(int p)
 88 {
 89     fs=0;
 90     dfs2(p,fa[p][0]);
 91     return fs;
 92 }
 93 struct node
 94 {
 95     int up;
 96     int rest;
 97 }stop[N];
 98 bool cmp1(node a,node b)
 99 {
100     return a.rest<b.rest;
101 }
102 bool cmp2(node a,node b)
103 {
104     return a.rest>b.rest;
105 }
106 bool cmp(int a,int b)
107 {
108     return a>b;
109 }
110 bool check(int time)
111 {
112     memset(stop,0,sizeof(stop));
113     memset(vis,0,sizeof(vis));
114     memset(q,0,sizeof(q));
115     cnt_a=0;
116     for(int i=1;i<=m;i++)
117     {
118         int time2=time;
119         int now=army[i];
120         bool can=0;
121         while(1)
122         {
123             for(int j=18;j>=0;j--)
124             {
125                 if(fa[now][j]&&F[now][j]<=time2)
126                 {
127                     time2-=F[now][j];
128                     now=fa[now][j];
129                     break;
130                 }
131                 if(j==0||now==1)
132                 {
133                     can=1;
134                     break;
135                 }
136             }
137             if(can)
138                 break;
139         }
140         if(now==1)
141         {
142             stop[++cnt_a].up=top[army[i]];
143             stop[cnt_a].rest=time2;
144         }
145         else
146             vis[now]=1;
147     }
148     sort(stop+1,stop+m+1,cmp1);
149     for(int i=1;i<=m;i++)
150     {
151         if(stop[i].rest<tdis[stop[i].up])
152         {
153             if(!vis[stop[i].up]&&check2(stop[i].up))
154             {
155                 vis[stop[i].up]=1;
156                 stop[i].rest=-1;
157             }
158         }
159     }
160     int tail=0;
161     sort(stop+1,stop+m+1,cmp2);
162     for(int i=head[1];i;i=nex[i])
163     {
164         int v=to[i];
165         if(!vis[v]&&check2(v))
166             q[++tail]=val[i];
167     }
168     sort(q+1,q+tail+1,cmp);
169     for(int i=1;i<=tail;i++)
170         if(stop[i].rest<q[i])
171             return false;
172     return true; 
173 }
174 int main()
175 {
176     int l, r;
177     scanf("%d",&n);
178     for(int i=1;i<n;i++)
179     {
180         int a, b, v;
181         scanf("%d%d%d",&a,&b,&v);
182         r+=v;
183         addedge(a,b,v);
184         addedge(b,a,v);
185     }
186     dfs(1,0);
187     for(int i=head[1];i;i=nex[i])
188     {
189         int p=to[i];
190         dfs1(p,1,p,val[i]);
191     }
192     update();
193     scanf("%d",&m);
194     for(int i=1;i<=m;i++)
195         scanf("%d",&army[i]);
196     int idx=0;
197     for(int i=head[1];i;i=nex[i])
198         if(to[i]!=1)
199             idx++;
200     if(m<idx)
201     {
202         printf("-1");
203         return 0;
204     }
205     l=0;
206     int ans;
207     while(l<r)
208     {
209         int mid=(l+r)>>1;
210         if(check(mid))
211             ans=mid,r=mid;
212         else
213             l=mid+1;
214     }
215     printf("%d",ans);
216     return 0;
217 }
View Code

   呃。。由于。。代码写的丑。。。在自己学校网站 (链接:https://neooj.com:8082/oldoj/)被卡了时间。。。。 于是有了下面的优化代码 (感谢@Yang1208

  1 #include <stdio.h>
  2 #include <algorithm>
  3 #include <string.h>
  4 using namespace std;
  5 #define O3 __attribute__((optimize("-O3")))
  6 const int N = 50005;
  7 const int root=1;
  8 const int logn = 19;
  9 int head[N];
 10 int to[N<<1];
 11 int nex[N<<1];
 12 int val[N<<1];
 13 int cnt,n,m;
 14 int fa[N][logn+1];
 15 int top[N];
 16 int tdis[N];
 17 int army[N];
 18 int dis[N];
 19 bool pos[N];
 20 int q[N];
 21 bool vis[N];
 22 int cnt_a;
 23 O3 char nc() {
 24     static char buf[100000],*p1,*p2;
 25     return p1==p2&&(p2=(p1=buf)+fread(buf,1,100000,stdin),p1==p2)?EOF:*p1++;
 26 }
 27 O3 inline int rd() {
 28     register int x=0;char s=nc();
 29     while(s<'0'||s>'9')s=nc();
 30     while(s>='0'&&s<='9')x=x*10+s-'0',s=nc();
 31     return x;
 32 }
 33 O3 void addedge(int a, int b,int v)
 34 {
 35     nex[++cnt]=head[a];
 36     head[a]=cnt;
 37     to[cnt]=b;
 38     val[cnt]=v;
 39 }
 40 O3 void dfs(int p,int f)
 41 {
 42     for(int i=head[p];i;i=nex[i])
 43     {
 44         if(to[i]!=f)
 45         {
 46             dis[to[i]]=dis[p]+val[i];
 47             fa[to[i]][0]=p;
 48             dfs(to[i],p);
 49         }
 50     }
 51 }
 52 O3 void update()
 53 {
 54     for(int j=1;j<=18;j++)
 55         for(int i=1;i<=n;i++)
 56             fa[i][j]=fa[fa[i][j-1]][j-1];
 57 }
 58 O3 void dfs1(int p,int f,int topf,int dist)
 59 {
 60     top[p]=topf;
 61     tdis[p]=dist;
 62     bool ft=0;
 63     for(int i=head[p];i;i=nex[i])
 64     {
 65         int v=to[i];
 66         if(v!=f)
 67         {
 68             ft=1;
 69             dfs1(v,p,topf,dist);
 70         }
 71     }
 72     if(!ft)
 73         pos[p]=1;
 74 }
 75 bool fs;
 76 O3 void dfs2(int p,int f)
 77 {
 78     if(pos[p])
 79     {
 80         fs=1;
 81         return ;
 82     }
 83     for(int i=head[p];i;i=nex[i])
 84     {
 85         int v=to[i];
 86         if(v!=f&&!vis[v])
 87         {
 88             dfs2(v,p);
 89             if(fs)
 90                 return ;
 91         }
 92     }
 93 }
 94 O3 inline bool check2(int p)
 95 {
 96     fs=0;
 97     dfs2(p,fa[p][0]);
 98     return fs;
 99 }
100 struct node
101 {
102     int up;
103     int rest;
104 }stop[N];
105 O3 inline bool cmp1(node a,node b)
106 {
107     return a.rest<b.rest;
108 }
109 O3 inline bool cmp2(node a,node b)
110 {
111     return a.rest>b.rest;
112 }
113 O3 inline bool cmp(int a,int b)
114 {
115     return a>b;
116 }
117 O3 bool check(int time)
118 {
119     memset(stop,0,sizeof(stop));
120     memset(vis,0,sizeof(vis));
121     memset(q,0,sizeof(q));
122     cnt_a=0;
123     for(int i=1;i<=m;i++)
124     {
125         int time2=time;
126         int now=army[i];
127         bool can=0;
128         while(1)
129         {
130             for(int j=18;j>=0;j--)
131             {
132                 if(fa[now][j]&&dis[now]-dis[fa[now][j]]<=time2)
133                 {
134                     time2-=dis[now]-dis[fa[now][j]];
135                     now=fa[now][j];
136                     break;
137                 }
138                 if(j==0||now==1)
139                 {
140                     can=1;
141                     break;
142                 }
143             }
144             if(can)
145                 break;
146         }
147         if(now==1)
148         {
149             stop[++cnt_a].up=top[army[i]];
150             stop[cnt_a].rest=time2;
151         }
152         else
153             vis[now]=1;
154     }
155     sort(stop+1,stop+m+1,cmp1);
156     for(int i=1;i<=m;i++)
157     {
158         if(stop[i].rest<tdis[stop[i].up])
159         {
160             if(!vis[stop[i].up]&&check2(stop[i].up))
161             {
162                 vis[stop[i].up]=1;
163                 stop[i].rest=-1;
164             }
165         }
166     }
167     int tail=0;
168     sort(stop+1,stop+m+1,cmp2);
169     for(int i=head[1];i;i=nex[i])
170     {
171         int v=to[i];
172         if(!vis[v]&&check2(v))
173             q[++tail]=val[i];
174     }
175     sort(q+1,q+tail+1,cmp);
176     for(int i=1;i<=tail;i++)
177         if(stop[i].rest<q[i])
178             return false;
179     return true; 
180 }
181 O3 int main()
182 {
183     int l, r;
184     n=rd();
185     for(int i=1;i<n;i++)
186     {
187         int a, b, v;
188         a=rd();b=rd();v=rd();
189         r+=v;
190         addedge(a,b,v);
191         addedge(b,a,v);
192     }
193     dfs(1,0);
194     for(int i=head[1];i;i=nex[i])
195     {
196         int p=to[i];
197         dfs1(p,1,p,val[i]);
198     }
199     update();m=rd();
200     for(int i=1;i<=m;i++) army[i]=rd();
201     int idx=0;
202     for(int i=head[1];i;i=nex[i])
203         if(to[i]!=1)
204             idx++;
205     if(m<idx)
206     {
207         printf("-1");
208         return 0;
209     }
210     l=0;
211     int ans;
212     while(l<r)
213     {
214         int mid=(l+r)>>1;
215         if(check(mid)) r=mid;
216         else l=mid+1;
217     }
218     printf("%d",l);
219     return 0;
220 }
View Code
posted @ 2018-08-23 20:37  sky20030724  阅读(251)  评论(2编辑  收藏  举报