2012Noip提高組Day2 T3 疫情控制
題目描述
H 國有 n 個城市,這 n 個城市用 n-1 條雙向道路相互連通構成一棵樹,1 號城市是首都,也是樹中的根節點。
H 國的首都爆發了一種危害性極高的傳染病。當局為了控制疫情,不讓疫情擴散到邊境城市(葉子節點所表示的城市),決定動用軍隊在一些城市建立檢查點,使得從首都到邊境城市的每一條路徑上都至少有一個檢查點,邊境城市也可以建立檢查點。但特別要註意的是,首都是不能建立檢查點的。
現在,在 H 國的一些城市中已經駐紮有軍隊,且一個城市可以駐紮多個軍隊。一支軍隊可以在有道路連接的城市間移動,並在除首都以外的任意一個城市建立檢查點,且只能在一個城市建立檢查點。一支軍隊經過一條道路從一個城市移動到另一個城市所需要的時間等於道路的長度(單位:小時)。
請問最少需要多少個小時才能控制疫情。註意:不同的軍隊可以同時移動。
輸入輸出格式
輸入格式:
第一行一個整數 n,表示城市個數。
接下來的 n-1 行,每行 3 個整數,u、v、w,每兩個整數之間用一個空格隔開,表示從城市 u 到城市 v 有一條長為 w 的道路。數據保證輸入的是一棵樹,且根節點編號為 1。
接下來一行一個整數 m,表示軍隊個數。
接下來一行 m 個整數,每兩個整數之間用一個空格隔開,分別表示這 m 個軍隊所駐紮的城市的編號。
輸出格式:
共一行,包含一個整數,表示控制疫情所需要的最少時間。如果無法控制疫情則輸出-1。
輸入輸出樣例
4 1 2 1 1 3 2 3 4 3 2 2 2輸出樣例#1:
3
說明
【輸入輸出樣例說明】
第一支軍隊在 2 號點設立檢查點,第二支軍隊從 2 號點移動到 3 號點設立檢查點,所需時間為 3 個小時。
【數據範圍】
保證軍隊不會駐紮在首都。
對於 20%的數據,2≤ n≤ 10;
對於 40%的數據,2 ≤n≤50,0<w <10^5;
對於 60%的數據,2 ≤ n≤1000,0<w <10^6;
對於 80%的數據,2 ≤ n≤10,000;
對於 100%的數據,2≤m≤n≤50,000,0<w <10^9。
這是一棵樹,我們可以很容易發現對於一支軍隊把他往樹根走是不影響他本身已經能夠封鎖的子樹的
另外我們還可以發現 對於一支軍隊越接近樹根越好,因為這樣他能封鎖的子樹可以盡可能的多
我們還可以發現 對於還沒有封鎖的子樹,我們必須外調可以調過來的軍隊來封鎖。
假設時間無現長 且軍隊足夠多的情況下肯定能控制疫情。
這是一個可行性的方案 時間可以二分。
如何知道哪些軍隊可以外調?
我們可以發現如果一個軍隊到了首都 還有時間可以繼續走,那就說明可以外調。
到這裏就有一個很明顯的貪心分配的方法了:
讓還剩時間多的軍隊走盡可能長的路
特別的,如果一個軍隊到了首都後 他原本封鎖的子樹不安全了(沒有軍隊了),且自己還剩下的時間不能再走回去那麽就讓他退一步。
如何把軍隊往上推到首都?
一步一步顯然過慢了
由於路徑是確定的,跟開車旅行一樣,倍增即可。
於是問題就可以解決了。
二分時間,判斷在這個時間裏能不能控制疫情,用倍增把軍隊往首都那推,然後把那些剩余時間不夠回去原來子樹的軍隊退回去,然後剩下的軍隊貪心分配就可以了。
至於不能控制疫情的情況,就是軍隊數小於根孩子個數,然而數據似乎並沒有這個數據(於是乎我也沒判了2333)
1 #include <cstring> 2 #include <cstdio> 3 #include <iostream> 4 #include <algorithm> 5 #define N 100005 6 using namespace std; 7 struct data{ 8 long long di; 9 int loc; 10 }em[N/2],li[N/2],cap[N/2]; 11 int num,n,m,next[N],to[N],head[N/2],fa[N],from[N/2],ca,lis,f[N/2][17],list[N/2]; 12 long long l,r,ti,up[N/2][17],ans,dis[N/2],power[N],w,sign[N/2],visit[N/2],unsafe[N/2]; 13 void add(int u,int v,long long w){ 14 num++; 15 next[num]=head[u]; 16 to[num]=v; 17 power[num]=w; 18 head[u]=num; 19 num++; 20 next[num]=head[v]; 21 to[num]=u; 22 power[num]=w; 23 head[v]=num; 24 } 25 void DFS(int x){ 26 for (int v,i=head[x];i;i=next[i]){ 27 v=to[i]; 28 if (!visit[v]&&(fa[x]!=v||x==1)){ 29 visit[v]=1; 30 fa[v]=x; 31 dis[v]=dis[x]+power[i]; 32 ti=ti<dis[v]?dis[v]:ti; 33 DFS(v); 34 } 35 } 36 } 37 void pre(){ 38 for (int i=1;i<=n;++i){ 39 f[i][0]=fa[i]; 40 up[i][0]=dis[i]-dis[fa[i]]; 41 } 42 for (int j=1;j<=16;++j) 43 for (int i=1;i<=n;++i){ 44 f[i][j]=f[f[i][j-1]][j-1]; 45 up[i][j]=dis[i]-dis[f[i][j]]; 46 } 47 } 48 bool cmp1(const struct data a,const struct data b){ 49 return (a.di>b.di); 50 } 51 bool cmp3(int a,int b){ 52 return (a>b); 53 } 54 void updata(int x,long long ti){ 55 int pos=li[x].loc; 56 long long qwq=ti; 57 for (int i=16;i>=0;--i) 58 if (up[pos][i]<=ti&&f[pos][i]!=1&&f[pos][i]!=0){ 59 ti-=up[pos][i]; 60 pos=f[pos][i]; 61 } 62 if (fa[pos]==1&&ti>=up[pos][0]) 63 from[x]=pos,cap[++ca].loc=x,cap[ca].di=ti-up[pos][0]; 64 else sign[pos]=qwq; 65 } 66 void check(int x,long long ti,int son){ 67 int qwq=0; 68 for (int i=head[x],v;i;i=next[i]){ 69 v=to[i]; 70 qwq++; 71 if (v==fa[x]) continue; 72 if (sign[v]==ti) continue; 73 if (x==1) check(v,ti,v); 74 else check(v,ti,son); 75 } 76 if (qwq==1) visit[son]=ti; 77 } 78 bool work(long long ti){ 79 lis=ca=0; 80 for (int i=1;i<=m;++i) 81 li[i]=em[i]; 82 for (int i=m;i>=1;--i) 83 updata(i,ti); 84 check(1,ti,0); 85 for (int i=head[1];i;i=next[i]) 86 if (visit[to[i]]==ti) unsafe[to[i]]=ti; 87 for (int i=1;i<=ca;++i) 88 if (cap[i].di<=dis[from[cap[i].loc]]&&unsafe[from[cap[i].loc]]==ti){ 89 cap[i].di=0; 90 unsafe[from[cap[i].loc]]=0; 91 } 92 sort(cap+1,cap+1+ca,cmp1); 93 while (cap[ca].di==0&&ca>0) ca--; 94 for (int i=head[1];i;i=next[i]) 95 if (unsafe[to[i]]==ti) list[++lis]=power[i]; 96 sort(list+1,list+1+lis,cmp3); 97 int l=1,r=1; 98 while (l<=ca&&r<=lis) 99 if (list[r]<=cap[l].di) l++,r++; 100 else break; 101 if (r>lis) return true; 102 else return false; 103 } 104 int main(){ 105 num=0; 106 scanf("%d",&n); 107 for (int u,v,i=1;i<n;++i){ 108 scanf("%d%d%lld",&u,&v,&w); 109 r+=w; 110 add(u,v,w); 111 } 112 scanf("%d",&m); 113 for (int i=1;i<=m;++i) 114 scanf("%d",&em[i].loc); 115 fa[1]=1; 116 DFS(1); 117 dis[1]=0; 118 fa[1]=1; 119 memset(visit,0,sizeof(visit)); 120 for (int i=1;i<=m;++i) 121 em[i].di=dis[em[i].loc]; 122 sort(em+1,em+1+m,cmp1); 123 pre(); 124 l=0; 125 ans=0; 126 while (l<r){ 127 ti=(l+r)>>1; 128 if (work(ti)) ans=ti,r=ti; 129 else l=ti+1; 130 } 131 if (l==r) if (work(l)) ans=l; 132 printf("%lld\n",ans); 133 return 0; 134 }神奇的代碼
(代碼寫的巨爛無比qwq)
2012Noip提高組Day2 T3 疫情控制