【noip2012】疫情控制


題意:

給出一顆n個節點有邊權的樹 和m個軍隊所在的位置 軍隊從某節點移動到相鄰節點要花費邊長度的時間 求最少要多少時間使得根節點(編號為1)到每個葉子的路徑上最少有一支軍隊(根節點不能有軍隊)

題解:

我們可以二分答案 那么問題就轉換為 在t的時間內軍隊能否控所有點

 

顯然一支軍隊在到根節點之前 如果能繼續向上走 那么這支軍隊能控制的點就會更多

維護bo[i]表示 從該點到所有該點子樹的葉子節點路徑上是否都有軍隊

對於每個不能走到根節點的軍隊 就讓他盡量向上走 直到不能走為止 將該點的bo值賦為1 然后可以用拓撲算出bo數組

這樣 根節點的所有兒子中bo為1的點就不用管 而剩下的點就需要派能走到根節點的軍隊到這些點控制

 

於是問題轉換為 有n0個點需要被控制 且控制該點需要Li的時間 還有m0支軍隊 每支軍隊有ti的時間 求這m0支軍隊是否能控制這n0個點

這原本這樣將L和t分別排序 貪心用兩個指針一個個掃就行了

但是要注意的是如果軍隊j就是從i點走到首都的 那么該軍隊不論有多少剩余時間都能控制該點(去年noip考試的時候好像就是沒想到這點)

這個問題我們只要做一個小轉換就行了 如果i點有軍隊從該點到達首都 那么用minarm[i]記下這些軍隊中剩余時間最少的是誰 當指針掃到i時先判斷minarm[i]是否被用過了 如果沒有 那么用minarm[i]來控制i 否則再在j指針上找軍隊

證明:如果minarm[i]沒被使用 那么t[j]>=t[minarm[i]] 所以在i點如果用minarm[i]則能省下一個剩余時間更多的軍隊 對於之后可能用到minarm[i]的點完全可以用j點代替

代碼:

  1 #include <cstdio>
  2 #include <cstring>
  3 #include <algorithm>
  4 using std::sort;
  5 const int N=50001;
  6 struct inli{
  7     int next,data,lon;
  8     inli(const int a=0,const int b=0,const int c=0):
  9         next(a),data(b),lon(c){}
 10 }line[N*2];
 11 struct info{
 12     int t,s;
 13     info(const int a=0,const int b=0):
 14         t(a),s(b){}
 15 }ar[N],ci[N];
 16 inline bool cmp(info a,info b){ return a.s>b.s; }
 17 int n,m,na,nc,fat[N],ti[N],gra[N],dis[N],arm[N],nl,son[N],mint[N],add,boo[N];
 18 int max(int x,int y){ return x>y ? x : y; }
 19 void dfs(int t){
 20     int res=-1,bo1=0,bo2=0;
 21     for (int i=son[t];i;i=line[i].next)
 22     if (line[i].data!=fat[t]){
 23         int ne=line[i].data;
 24         dfs(ne);
 25         if (ti[ne]==-1) bo2=1;
 26         if (ti[ne]-line[i].lon>=0) bo1=1;
 27         res=max(res,ti[ne]-line[i].lon);
 28     }
 29     if (t!=1 && line[son[t]].next){
 30         if (bo1) ti[t]=max(ti[t],res);
 31         else if (bo2) ti[t]=max(ti[t],-1);
 32         else ti[t]=max(ti[t],0);
 33     }
 34 }
 35 void maketi(int t){
 36     for (int i=1;i<=m;i++)
 37     if (dis[arm[i]]>=t) ti[arm[i]]=t;
 38     dfs(1);
 39 }
 40 void makear(int t){
 41     na=0;
 42     for (int i=1;i<=m;i++)
 43     if (dis[arm[i]]<t) ar[++na]=info(gra[arm[i]],t-dis[arm[i]]);
 44     sort(ar+1,ar+na+1,cmp);
 45     for (int i=1;i<=na;i++){
 46         int x=ar[i].t;
 47         if (mint[x]==0) mint[x]=i;
 48         else if (ar[mint[x]].s>ar[i].s) mint[x]=i;
 49     }
 50 }
 51 void makeci(){
 52     nc=0;
 53     for (int i=son[1];i;i=line[i].next)
 54     if (ti[line[i].data]==-1) ci[++nc]=info(line[i].data,line[i].lon);
 55     sort(ci+1,ci+nc+1,cmp);
 56 }
 57 bool work(){
 58     if (na<nc) return 0;
 59     memset(boo,0,sizeof(boo));
 60     for (int i=1,j=1;i<=nc;i++)
 61     if (!boo[mint[ci[i].t]] && mint[ci[i].t]) boo[mint[ci[i].t]]=1;
 62     else{
 63         while (boo[j] && j<=na) ++j;
 64         if (j>na) return 0;
 65         if (ar[j].s<ci[i].s) return 0;
 66         boo[j++]=1;
 67     }
 68     return 1;
 69 }
 70 bool check(int t){
 71     memset(ti,-1,sizeof(ti));
 72     memset(mint,0,sizeof(mint));
 73     maketi(t);
 74     makear(t);
 75     makeci();
 76     return work();
 77 }
 78 int getans(){
 79     int l=-1,r=1000000000,mid;
 80     while (l+1<r){
 81         mid=(l+r)/2;
 82         if (check(mid)) r=mid;
 83         else l=mid;
 84     }
 85     return r;
 86 }
 87 void makefat(int t){
 88     for (int i=son[t];i;i=line[i].next)
 89     if (line[i].data!=fat[t]){
 90         int ne=line[i].data;
 91         if (t==1) gra[ne]=ne;
 92         else gra[ne]=gra[t];
 93         fat[ne]=t;
 94         dis[ne]=dis[t]+line[i].lon;
 95         makefat(ne);
 96     }
 97 }
 98 int main(){
 99     freopen("blockade.in","r",stdin);
100     freopen("blockade.out","w",stdout);
101     scanf("%d",&n);
102     for (int x,y,z,i=1;i<n;i++){
103         scanf("%d%d%d",&x,&y,&z);
104         line[++nl]=inli(son[x],y,z),son[x]=nl;
105         line[++nl]=inli(son[y],x,z),son[y]=nl;
106         if (x==1 || y==1) ++add;
107     }
108     makefat(1);
109     scanf("%d",&m);
110     if (m<add){
111         printf("-1");
112         return 0;
113     }
114     for (int i=1;i<=m;i++) scanf("%d",&arm[i]);
115     sort(arm+1,arm+m+1);
116     printf("%d",getans());
117     fclose(stdin);
118     fclose(stdout);
119 }
View Code

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM