zoukankan      html  css  js  c++  java
  • luogu 1084 疫情控制

     

    分析

     时隔多年再一次拿起这道题

    求能控制疫情时,用时最长的的军队的时间最短,

    一般二分

    发现军队所用时间与距离成正比

    而能控制的人数也大致随之单调

    嗯,铁定二分

    为什么?

    明显,父亲控制的节点绝对不小于儿子

    尽量把军队往上走就好

    首都不能放军队

    能够跳到首都的,要么就留在自己这个子树,要么去控制其他子树

    废话

    先染色,把没有覆盖完的子树的根(首都的儿子)处理出来

    把可以跳到首都的军队及其子树记录下来

    然后,贪心

    明显,先将剩余时间短的军队派出去,方案会更优,剩余时间大的作用范围更大,选择余地更多

    剩余时间短的,配对距离短的

    这题,细节挺多

    代码

      1 /*********************
      2 User:Mandy.H.Y
      3 Language:c++
      4 Problem:luogu 1084
      5 Algorithm:
      6 *********************/
      7 
      8 #include<bits/stdc++.h>
      9 
     10 using namespace std;
     11 
     12 const int maxn = 5e4 + 5;
     13 
     14 int n,size,first[maxn],cnt;
     15 int m,father[maxn][18];
     16 long long dis[maxn][18];
     17 bool vis[maxn];
     18 long long sumw = 0;
     19 int army[maxn];
     20 int anc[maxn];//表示这颗子树的根是首都的哪个儿子 
     21 
     22 struct Node{
     23     int res,anc;
     24 }cur[maxn];
     25 
     26 struct Edge{
     27     int v,w,nt;
     28 }edge[maxn << 1],ee[maxn];
     29 
     30 template<class T>inline void read(T &x){
     31     x = 0;bool flag = 0;char ch = getchar();
     32     while(!isdigit(ch)) flag |= ch == '-',ch = getchar();
     33     while(isdigit(ch)) x = (x << 1) + (x << 3) + (ch ^ 48),ch = getchar();
     34     if(flag) x = -x;
     35 }
     36 
     37 template<class T>void putch(const T x){
     38     if(x > 9) putch(x / 10);
     39     putchar(x % 10 | 48);
     40 }
     41 
     42 template<class T>void put(const T x){
     43     if(x < 0) putchar('-'),putch(-x);
     44     else putch(x);
     45 }
     46 
     47 void file(){
     48     freopen("testdata(2).in","r",stdin);
     49 //    freopen("1084.out","w",stdout);
     50 }
     51 
     52 void eadd(int u,int v,int w){
     53     edge[++size].v = v;
     54     edge[size].w = w;
     55     edge[size].nt = first[u];
     56     first[u] = size;
     57 }
     58 
     59 void readdata(){
     60     read(n);
     61     for(int i = 1;i < n; ++ i){
     62         int u,v,w;
     63         read(u);read(v);read(w);
     64         eadd(u,v,w);
     65         eadd(v,u,w);
     66         sumw += w;
     67     }
     68     read(m);
     69     for(int i = 1;i <= m; ++ i ) read(army[i]);
     70 }
     71 
     72 void dfs(int u,int fa,int a){
     73     father[u][0] = fa;
     74     anc[u] = a;
     75     for(int i = 1;i <= 17; ++ i) 
     76         father[u][i] = father[father[u][i-1]][i-1],
     77         dis[u][i] = dis[u][i-1]+dis[father[u][i-1]][i-1];//倍增存距离 
     78     for(int i = first[u];i;i = edge[i].nt){
     79         int v = edge[i].v;
     80         int w = edge[i].w,ac;
     81         if(v == fa) continue;
     82         dis[v][0] = (long long)w;
     83         if(!a) ac = v;
     84         else ac = a;
     85         anc[v] = ac;//主要是首都的儿子的根就是自己 
     86         dfs(v,u,ac);
     87     }
     88 }
     89 
     90 void check_dfs(int u,int fa){
     91     vis[u] = vis[u] | vis[fa];//从父亲继承 
     92     bool judge = 1,son = 0;
     93     for(int i = first[u];i;i = edge[i].nt){
     94         int v = edge[i].v;
     95         if(v == fa) continue;
     96         son = 1;//不是叶子 
     97         check_dfs(v,u);
     98         if(!vis[v]) judge = 0;
     99         //儿子都被覆盖完了,相当于这颗子树被覆盖 
    100     }
    101     if(son) vis[u] |= judge;//不是叶子的节点才能用儿子标记 
    102 }
    103 
    104 bool cmp(const Node &a,const Node &b){
    105     return a.res > b.res ;
    106 }
    107 
    108 bool cmp1(const Edge &a,const Edge &b){
    109     return a.w < b.w ;
    110 }
    111 
    112 bool check(long long x){
    113     memset(vis,0,sizeof(vis));
    114     cnt = 0;
    115     for(int i = 1;i <= m; ++ i){
    116         int u = army[i];
    117         int fa = u;
    118         long long res = 0;
    119         for(int j = 17;j >= 0; --j){//倍增往上跳 
    120             if(father[u][j] && res+dis[u][j] <= x){
    121                 //father不能是0 
    122                 fa = father[u][j];
    123                 res += dis[u][j];
    124                 u = fa;//跳到不能跳为止 
    125             }
    126         }
    127         if(fa == 1){
    128             cur[++cnt].res = res;
    129             cur[cnt].anc = anc[army[i]];//u已经改变了 ,可能变成1 
    130         } else vis[fa] = 1;
    131     }
    132     check_dfs(1,0);//标记已经被完全覆盖的子树 
    133     int num = 0;
    134     for(int i = first[1];i;i = edge[i].nt){
    135         int v = edge[i].v;
    136         int w = edge[i].w;
    137         if(vis[v]) continue;
    138         ee[++num].w = w;
    139         ee[num].v = v;
    140     }
    141     sort(ee + 1,ee + num + 1,cmp1);//从小到大 
    142     sort(cur + 1,cur + cnt + 1,cmp);//从大到小 
    143     //用的时间长 = 剩余时间短 
    144     int j = 1;
    145     for(int i = 1;i <= num; ++ i){//枚举没被覆盖的子树 
    146         if(vis[ee[i].v]) continue;//可能有些待在自己子树的已经被覆盖 
    147         while(ee[i].w + cur[j].res > x && ee[i].v != cur[j].anc && j <= cnt) {
    148             vis[cur[j].anc] = 1;//不能去其他子树的,就待在自己子树就好 
    149             ++j;
    150         }
    151         if(j > cnt) break;
    152         vis[ee[i].v] = 1;
    153         ++j;
    154     }
    155     for(int i = first[1];i;i = edge[i].nt){
    156         int v = edge[i].v;
    157         if(!vis[v]){
    158             return 0;
    159         }
    160     }
    161     return 1;
    162 }
    163 
    164 void work(){
    165     dfs(1,0,0);
    166     long long l,r,ans = 0;
    167     l = 0,r = sumw;
    168     while(l <= r){
    169         long long mid = (l + r) >> 1;
    170         if(check(mid)) ans = mid,r = mid - 1;
    171         else l = mid + 1;
    172     }
    173     put(ans);
    174 }
    175 
    176 int main(){
    177 //    file();
    178     readdata();
    179     work();
    180     return 0;
    181 }
    View Code
  • 相关阅读:
    Linux 安装多版本Python
    ElasticSearch 镜像 & 安装 & 简易集群
    SpringBoot-异步调用@Async
    SprinigBoot整合Kafka
    Kafka快速安装部署
    Linux-JDK安装
    npm / yarn 配置镜像、使用方法
    React搭建项目(全家桶)
    原生JS 将canvas生成图片
    原生 JS 的 Base64 转码
  • 原文地址:https://www.cnblogs.com/Mandy-H-Y/p/11497303.html
Copyright © 2011-2022 走看看