• 【NOIP2012 day2】疫情控制


    问题:

    H 国有 n 个城市,这 n 个城市用 n-1 条双向道路相互连通构成一棵树,1 号城市是首都,也是树中的根节点。
    H 国的首都爆发了一种危害性极高的传染病。当局为了控制疫情,不让疫情扩散到边境城市(叶子节点所表示的城市),决定动用军队在一些城市建立检查点,使得从首都到边境城市的每一条路径上都至少有一个检查点,边境城市也可以建立检查点。但特别要注意的是,首都是不能建立检查点的。现在,在 H国的一些城市中已经驻扎有军队,且一个城市可以驻扎多个军队。

    一支军队可以在有道路连接的城市间移动,并在除首都以外的任意一个城市建立检查点,且只能在一个城市建立检查点。一支军队经过一条道路从一个城市移动到另一个城市所需要的时间等于道路的长度(单位:小时)。请问最少需要多少个小时才能控制疫情。注意:不同的军队可以同时移动。

    解:

    很早之前就一直在做这道题,但当时我还很ruo , 打了很久都过不了,又不知道怎么做,在经历了各种树上复习和做题后昨天我突然醒悟  敲敲打打 调调改改 终于过掉了这道题,超级感动。来写下我的思路

    首先我们先看题

    正难则反 考虑向上倍增

    题目要求最短的时间内覆盖所有叶子节点 显然是二分答案  覆盖所有叶子节点 显然是在最短时间内 让军队尽量跳倍增距离 离根节点越近越好  那么假如点跳不到根节点 那么就让他停在那里 若跳到了根节点 那么就记录下来

    然后DFS 一下 O(n) 查找未覆盖叶子节点的根节点的儿子节点 记录下来 

    至于贪心

    将两个数组存下来  从小到大 排序 贪心一下 最小的分配最小 最大的分配最大

    若当前的根节点存在军队 跳上来的根节点的儿子节点没有被覆盖到 那么就去 覆盖这个点 显然更优

    至于距离倍增

    好久没打 太生疏啦

    $DIS[i][j]$表示$ i$节点跳 $2^j$个节点所经过的距离

    距离倍增

    ll go_up(ll s,int x)   
    {   
        int k=ceil(log2(dep[x]));   
        for(int i=k;i>=0;i--)   
        {   
            if(f[x][i]&&s>=(dis[x][i])) {s-=dis[x][i];x=f[x][i];}   //注意顺序不要颠倒
        }   
        return x;   
    }   

    好了放code:

    #include<stdio.h>
    #include<bits/stdc++.h>   
    using namespace std;   
    #define maxnn 120000  
    #define ll long long 
    int n,m;   
    int las[maxnn],nex[maxnn],en[maxnn],le[maxnn],tot;   
    int f[maxnn][70];   
    int arm[maxnn],armre[maxnn];   
    int dep[maxnn];   
    int mark[maxnn],mask[maxnn],mark1[maxnn];   
    ll  dis1[maxnn];   
    ll dis[maxnn][60];   
    int size[maxnn];  
    int tot1=0;  
    typedef pair<ll ,ll > P;   
    P a[maxnn],maj[maxnn];int c[maxnn];   
    int cnt=0;   
    
    void add(int a,int b,ll c)   
    {   
        en[++tot]=b;   
        nex[tot]=las[a];   
        las[a]=tot;   
        le[tot]=c;  
    }   
    ll go_up(ll s,int x)   
    {   
        int k=ceil(log2(dep[x]));   
        for(int i=k;i>=0;i--)   
        {   
            if(f[x][i]&&s>=(dis[x][i])) {s-=dis[x][i];x=f[x][i];}   
        }   
        return x;   
    }   
    void dfs(int v,int fa,ll l)   
    {   
        dep[v]=dep[fa]+1;   
        dis[v][0]=l;   
        dis1[v]=dis1[fa]+l;   
        f[v][0]=fa;   
        size[v]=1;  
        int s=ceil(log2(dep[v]));   
        for(int i=1;i<=s;i++)   
        {   
            f[v][i]=f[f[v][i-1]][i-1];   
            dis[v][i]=dis[v][i-1]+dis[f[v][i-1]][i-1];   
        }   
        for(int i=las[v];i;i=nex[i])   
        {   
            int u=en[i];   
            if(u!=f[v][0])   
            {   
                dfs(u,v,le[i]);  
                size[v]+=size[u];   
            }   
        }   
    }   
    bool  dfs1(int fff,int v)   
    {   int fla=1;
          if(mark1[v]) c[v]=fff;   
        if(mark[v]) return true;  
        if((size[v]==1)&&(!(mark[v])))  return false;       
        else    
        {   
        
            for(int i=las[v];i;i=nex[i])   
            {   
                    int u=en[i];   
                    if(u!=f[v][0])   
                    {   
                       if(!dfs1(fff,u)) fla=0;   //这里开始存在问题  卡了好久
                    }   
            }   
        }
        if(fla==0) return false;   
        return true;   
    }   
    bool isok(long long ttt)   
    {   
        tot1=0;cnt=0;  
        for(int i=1;i<=n;i++) mark[i]=0,mark1[i]=0,mask[i]=0;   
        for(int i=1;i<=m;i++)   
        {   
            armre[i]=go_up(ttt,arm[i]);   
            if(armre[i]==1) {mark1[arm[i]]=1; a[++tot1].first=ttt-dis1[arm[i]],a[tot1].second=arm[i];}   
            else mark[armre[i]]=1;   
        }   
        for(int i=las[1];i;i=nex[i])   
        if(!dfs1(en[i],en[i]))   
        {   
            maj[++cnt].first=le[i];   
            maj[cnt].second=en[i]; 
            mask[en[i]]=1;   
        }   
        int i=1,j=1;   
        sort(a+1,a+1+tot1);  
        sort(maj+1,maj+1+cnt);  
        while(i<=tot1&&j<=cnt)   
        {   
            if(a[i].first>=maj[j].first&&mask[maj[j].second])    
            {   
                if(mask[c[a[i].second]]) mask[c[a[i].second]]=0,i++;   
                else  mask[maj[j].second]=0,i++,j++;   
            }   
            else   
            {   
                if(!mask[maj[j].second]) j++;   
                else    
                if(a[i].first<maj[j].first)  
                { 
                     if(mask[c[a[i].second]]) mask[c[a[i].second]]=0,i++;   
                     else    i++; 
                } 
            }   
        }   
         j=0; 
        for(int i=1;i<=cnt;i++) if(!mask[maj[i].second])j++; 
        return j>=cnt;   
    }   
    int main()   
    {   
    //freopen("xie.txt","r",stdin); 
    //freopen("xiee.txt","w",stdout); 
        int x,y,z;   
        cin>>n;   
        ll l=0,r=1800000000;   
        for(int i=1;i<n;i++)   
        {   
            scanf("%d%d%d",&x,&y,&z);   
            add(x,y,z);   
            add(y,x,z);   
        }   
        cin>>m;   
        dfs(1,0,0);   
        for(int i=1;i<=m;i++)   
        {   
            scanf("%d",&arm[i]);   
        }   
        while(l<=r)   
        {   
            ll mid=(l+r)/2;   
            if(isok(mid))r=mid-1;   
            else l=mid+1;   
        }   
        if(l<=1800000000) 
        cout<<l;   
        else 
        cout<<-1; 
    }
    刀剑映出了战士的心。而我的心,漆黑且残破
  • 相关阅读:
    键盘输入thisisunsafe
    vscode
    iterm2 rz sz
    homebrew镜像更换
    mac
    homebrew下载不成功
    shutil:高层文件操作
    tempfile:临时文件系统对象
    linecache:读取文本文件的指定内容
    fnmatch:Unix式glob模式匹配,简单场景下可以代替正则
  • 原文地址:https://www.cnblogs.com/OIEREDSION/p/11375248.html
Copyright © 2020-2023  润新知