• noip模拟赛 软件software


    地图上的 n个城市,由 n-1条道路连接,且任意两个城市连通。
    除 1号城市之外的每个都有 一台计算机,安装软件号城市之外的每个都有 一台计算机,安装软件一个 自己的安装时间。
    住在 1号城市的蒟蒻要给这 n-1台计算机装配软件,他可以沿着 n-1条道路 行走,每条道路花费的时间为 1。
    蒟蒻在第 0时刻出发,他每走到一个城市就立给该的电脑装软件。
    因为蒟蒻急着回家,所以他希望在最快到,因为蒟蒻急着回家,所以他希望在最快到 1号城市的基础上,所有电脑完 号城市的基础上,所有电脑完成。

    【数据规模和约定】
    对于 30%的数据,2<=n<=10,1<=每台计算机安装软件时间<=100;
    对于 60%的数据,2<=n<=1000,1<=每台计算机安装软件时间<=100000;
    对于 100%的数据,2<=n<=500000,1<=每台计算机安装软件的时间<=10^9。

    注意一定要保证回去时间最小,图又是一颗树,所以每条边一定经过两次,而一旦到达一个点,一定要遍历完当前点的所有子树再返回。
    这道题设L[k]为从k开始,按照最优决策遍历完所有k的子树,所有软件完成安装所需的最小时间。s[k]是k的子树大小。
    注意到这样一个问题,若当前节点有两种选择,1和2,我们所需要做的决策就是
    max(l[1],l[2]+2*s[1]),max(l[1]+2*s[2],l[2])这两个数哪一个小,就选小的决策,其中第一个代表先走1,第二个代表先走2。
    假设一个节点有q个子树,我们做出了q个决策,那么显然,交换任意两个相邻的决策顺序不会影响其它决策,然后多做几次,选出一个最优的决策。
    我的方法是证明在这q个子树中,第一步要么走l最大的,要么走l次大的。因为不走l最大的的原因是其size过大,而毫无疑问,这个事件对l次大的影响是最大的,所以结论成立。
    然后按l排序,for i=2 to n,判断每个和第1个哪个更优,更优的就取走,bas+=2*s[k],剩下的没被取走的就作为第一个。

    PS:这题略卡常,用vector存图会TLE

     1 #include<cstdio>
     2 #include<algorithm>
     3 #define maxn 500005
     4 using namespace std;
     5 int fa[maxn];
     6 long long size[maxn],x[maxn],t[maxn],n,m,head[maxn],cnt,sf[maxn];
     7 struct edge{int to,next;}e[4*maxn];
     8 void insert(int u,int v){
     9     e[++cnt].to=v;e[cnt].next=head[u];head[u]=cnt;
    10     e[++cnt].to=u;e[cnt].next=head[v];head[v]=cnt;
    11 }
    12 struct sd{
    13     int u;long long v;
    14     bool operator < (const sd & g1) const{
    15     return v>g1.v;}
    16 }q[4*maxn];
    17 long long read(){
    18     long long ret=0;char ch=getchar();
    19     while(ch<'0'||ch>'9') ch=getchar();
    20     while(ch>='0'&&ch<='9') ret=ret*10+ch-'0',ch=getchar();
    21     return ret;
    22 }
    23 void dfs(int k,int f){
    24     fa[k]=f;
    25     for(int i=head[k];i;i=e[i].next){
    26         if(e[i].to==f) continue;
    27         dfs(e[i].to,k);
    28         size[k]+=size[e[i].to];
    29     }size[k]++;
    30 }
    31 void dfs2(int k,int bas){
    32     long long h,tot=bas;
    33     for(int i=head[k];i;i=e[i].next){
    34         if(e[i].to==fa[k]) continue;
    35         dfs2(e[i].to,tot);tot++;
    36         q[tot].u=e[i].to;
    37         q[tot].v=t[e[i].to];
    38     }
    39     t[k]=max(t[k],sf[k]);
    40     if(!(tot-bas)) return;
    41     sort(q+bas+1,q+tot+1);long long bsi=1;
    42     for(int i=bas+2;i<=tot;i++){
    43         if(q[bas+1].v+2*size[q[i].u]<q[i].v+2*size[q[bas+1].u]){
    44             t[k]=max(t[k],q[i].v+bsi);
    45             bsi+=2*size[q[i].u];
    46         }
    47         else{
    48             t[k]=max(t[k],q[bas+1].v+bsi);
    49             bsi+=2*size[q[bas+1].u];
    50             q[bas+1].v=q[i].v;q[bas+1].u=q[i].u;
    51         }
    52     }
    53     t[k]=max(t[k],t[q[bas+1].u]+bsi);
    54 }
    55 int main(){
    56     freopen("software.in","r",stdin);
    57     freopen("software.out","w",stdout);
    58     n=read();
    59     for(int i=2;i<=n;i++)sf[i]=read();long long a,b;
    60     for(int i=1;i<n;i++){
    61         a=read();b=read();
    62         insert(a,b);
    63     }
    64     dfs(1,0);
    65     dfs2(1,0);
    66     printf("%lld
    ",t[1]);
    67     return 0;
    68 }

     

  • 相关阅读:
    Internet Explorer 11:不要再叫我IE
    C#汉字转拼音
    winfrom设置当前画面始终显示在最前面
    解决 winform打开网页 和WebBrowser打开链接360误报拦截的问题
    dataGridView使用指南系列一、回车换行或换列完美解决方案
    C#--WinForm项目主窗体设计
    C#后台解析 json 动态解析 通用(Dictionary)
    在windows下安装git中文版客户端并连接gitlab
    检测到在集成的托管管道模式下不适用的ASP.NET设置的解决方法(非简单设置为【经典】模式)
    关闭窗体后,进程仍然在运行的问题重现与解决
  • 原文地址:https://www.cnblogs.com/awipppp/p/5956977.html
Copyright © 2020-2023  润新知