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

洛谷P1084 疫情控制

LCA毒瘤題

一個很顯然的性質,一個點儘量向上跑,可以阻斷更多的子樹

還有就是這種求最小啊最大啊的題,都可以二分答案

於是我們得到了一個優秀的做法,二分答案,然後去判斷是否合法

如何判斷

我們用倍增的方法,讓每個軍隊在mid的時間內儘可能向上跳,直到到達根節點或者不能向上跳為止,然後我們把每個能到根節點的軍隊放到一個數組裡,並記錄下他還能走多遠,因為他還能夠去到其他點,然後我們能到的點打上vis標記,然後對於能從根節點且未被打上標記的點,我們也存到一個數組裡,然後對於這些沒被控制的點,顯然它可以由本來就在它的子樹裡,但是到了根節點的軍隊控制,也可以由根節點下來的軍隊控制,顯然讓這兩個裡面剩餘路徑 大的來控制更優,於是乎,我們就優先讓剩餘路徑大的軍隊匹配距離遠的未被控制點就吼了

程式碼

//By AcerMo
#include<cmath>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
const int M=100500; 
struct rot{int now,tp;}can[M];
int n,m,lef,tot;
bool vis[M];
int to[M],nxt[M],w[M],head[M],cnt;
int dep[M],f[M][20],id[M],d[M][20
],top[M],ono[M]; inline int read() { int x=0;char ch=getchar(); while (ch>'9'||ch<'0') ch=getchar(); while (ch>='0'&&ch<='9') x=x*10+ch-'0',ch=getchar(); return x; } inline void add(int x,int y,int z) { to[++cnt]=y;w[cnt]=z;nxt[cnt]=head[x];head[x]=cnt; to[++cnt]=x;w[cnt]=z;nxt[cnt]=head[y];head[y]=cnt; return
(void)(lef+=(x==1||y==1),tot+=z); } inline bool cmp1(rot a,rot b){return a.now<b.now;} inline bool cmp2(rot a,rot b){return a.now>b.now;} inline bool cmp3(int a,int b){return a>b;} inline void dfs(int x,int fa,int t) { f[x][0]=fa;dep[x]=dep[fa]+1;top[x]=t; for (int i=1;i<=18;i++) f[x][i]=f[f[x][i-1]][i-1], d[x][i]=d[x][i-1]+d[f[x][i-1]][i-1]; for (int i=head[x];i;i=nxt[i]) if (to[i]!=fa) d[to[i]][0]=w[i],dfs(to[i],x,x==1?to[i]:t); return ; } inline bool jud(int x,int fa) { if (vis[x]) return 1; int all=0; for (int i=head[x];i;i=nxt[i]) if (to[i]!=fa) { all++; if (!jud(to[i],x)) return 0; } return all!=0; } inline bool che(int e) { fill(vis,vis+n+1,0);int all=0; for (int i=1;i<=m;i++) { int x=id[i],dis=e; for (int k=18;k>=0;k--) { if (!f[x][k]||d[x][k]>dis) continue; dis-=d[x][k]; if (f[x][k]==1) { can[++all].tp=top[x];x=f[x][k]; can[all].now=dis;break; } x=f[x][k]; } vis[x]=1; } vis[1]=0; if (jud(1,1)) return 1; sort(can+1,can+all+1,cmp1); for (int i=1;i<=all;i++) if (can[i].now<d[can[i].tp][0]) if (!jud(can[i].tp,1)) can[i].now=-1,vis[can[i].tp]=1; sort(can+1,can+all+1,cmp2); can[all+1].now=-1e12;all=0; for (int i=head[1];i;i=nxt[i]) if (!jud(to[i],1)) ono[++all]=w[i]; sort(ono+1,ono+all+1,cmp3); for (int i=1;i<=all;i++) if (ono[i]>can[i].now) return 0; return 1; } signed main() { n=read();int x,y,z; for (int i=1;i<n;i++) x=read(),y=read(),z=read(),add(x,y,z); dfs(1,0,0);m=read(); if (lef>m) return puts("-1"),0; for (int i=1;i<=m;i++) id[i]=read(); int l=0,r=tot; while (l<r) { int mid=(l+r)>>1; if (!che(mid)) l=mid+1; else r=mid; } cout<<l; return 0; }