zoukankan      html  css  js  c++  java
  • 【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
  • 相关阅读:
    初学C#线程
    初学C#线程二
    JQuery Ajax
    算法测试
    个人报告
    202120221课程设计第三周进展
    socket测试3
    202120221课程设计任务理解与分工
    嵌入式基础
    202120221课程设计第四周进展
  • 原文地址:https://www.cnblogs.com/g-word/p/3370085.html
Copyright © 2011-2022 走看看