zoukankan      html  css  js  c++  java
  • 树(tree)

    树(tree)

    题目描述

     

    给定一棵nn个节点的树,树上每个点有点权xixi 。

    对于一条路径i1,i2,…,ik,定义路径的权值为xi1×xi2×⋯×xik/k

    现在要找一条权值最小的路径,请以分数的形式输出路径的权值。

     

    输入

     

    第一行包括一个整数nn。

    第二行到第nn行每行两个整数x,y(1≤x,y≤n)x,y(1≤x,y≤n),表示一条xx到yy的树边。

    第n+1n+1行到第2n2n行,依次为x1,x2,…,xnx1,x2,…,xn。

     

    输出

     

    输出答案的分数形式,形如a/ba/b,其中a,ba,b互质且为正整数。

     

    样例输入

    6 
    1 2 
    1 3 
    2 6 
    3 4 
    3 5 
    1 
    1 
    2 
    3 
    1 
    1

    样例输出

    1/3

    提示

     

    对于100%100%的数据,n≤106,xi≤109n≤106,xi≤109。

    测试点编号

    nn

    其它性质

    1,2,3,41,2,3,4

    103103

     

    5,6,75,6,7

    106106

    不存在一个节点的度数超过22

    8,9,108,9,10

    106106

     

     

     

    来源

    南外NOIP2017模拟


    这题有点诡异。。。

    如果整棵树上的最小值大于一,答案就是最小值,因为乘起来除以2肯定不优

    那么我们考虑树上最长的1的序列

    如果有111121111这样若干1夹一个2的答案,那么它可能是答案。

    不然就是最长1的序列。

    证明的话,分分类吧。。

    #include<cstdio>
    #include<iostream>
    #include<cstdlib>
    #include<cstring>
    #include<algorithm>
    #include<cmath>
    #define maxn 1000005
    using namespace std;
    int n,head[maxn],f[maxn],g[maxn],up[maxn],w[maxn];
    int fl,tot,t1,t2,ans1,ans2;
    struct node{
        int v,nex;
    }e[maxn*2];
    void lj(int t1,int t2){
        e[++tot].v=t2;e[tot].nex=head[t1];head[t1]=tot;
    }
    void dfs(int k,int fa){
        int Max=0,max2=0;
        for(int i=head[k];i;i=e[i].nex){
            if(e[i].v!=fa){
                dfs(e[i].v,k);
                if(f[e[i].v]>Max){
                    max2=Max;
                    Max=f[e[i].v];
                }
                else if(f[e[i].v]>max2)max2=f[e[i].v];
            }
        }
        if(w[k]==1){
            f[k]=Max+1;
            if(max2>0)g[k]=max2+1;
        }
        else f[k]=g[k]=0;
    }
    void dfs2(int k,int fa){
        if(w[fa]!=1)up[k]=0;
        else {
            if(f[fa]==f[k]+1)up[k]=g[fa];
            else up[k]=f[fa];
            up[k]=max(up[k],up[fa]+1);
        }
        for(int i=head[k];i;i=e[i].nex){
            if(e[i].v!=fa){
                dfs2(e[i].v,k);
            }
        }
    }
    void work(int k,int fa){
        if(w[k]==1){
            ans1=max(ans1,max(f[k]+g[k]-1,f[k]+up[k]));
            //cout<<k<<' '<<f[k]<<' '<<g[k]<<' '<<max(f[k]+g[k]-1,f[k]+up[k])<<endl;
        }
        if(w[k]==2){
             
            int ma=0;
            for(int i=head[k];i;i=e[i].nex){
                if(e[i].v!=fa)ma=max(ma,f[e[i].v]);
            }
            ans2=max(ans2,max(ma+g[k]-1,ma+up[k]));
        }
        for(int i=head[k];i;i=e[i].nex){
            if(e[i].v!=fa){
                work(e[i].v,k);
            }
        }
    }
    int main(){
        freopen("tree.in","r",stdin);
        freopen("tree.out","w",stdout);
        cin>>n;
        for(int i=1;i<n;i++){
            scanf("%d%d",&t1,&t2);
            lj(t1,t2);lj(t2,t1);
        }
        int Min=1e9;
        for(int i=1;i<=n;i++){
            scanf("%d",&w[i]);
            Min=min(Min,w[i]);
        }
        if(Min>1){printf("%d/1
    ",Min);return 0;}
        dfs(1,0);
        dfs2(1,0);up[1]=0;
        //for(int i=1;i<=n;i++)cout<<i<<' '<<f[i]<<' '<<g[i]<<' '<<up[i]<<endl;
        work(1,0);
        ans2++;
        if(ans1*2>=ans2){
            printf("1/%d
    ",ans1);
        }
        else {
            if(ans2%2==0){
                ans2/=2;
                printf("1/%d
    ",ans1);
            }
            else printf("2/%d
    ",ans2);
        }
        return 0;
    }
  • 相关阅读:
    关于OutputStream的write方法FAQ(from bbs.csdn.net)
    【Java】对文件或文件夹进行重命名
    [复习] JAVA 遍历目录 (递归调用和非递归)
    [科普]关于文件头的那些事
    Intellij IDEA和EclipsE之间的的全面对比
    为什么43%前端开发者想学Vue.js
    Chrome调试ECMAScript之断点debug技巧大全!
    如何Vue-cli开始使用在Vue.js项目中启动TDD(测试驱动开发)
    toString() 和 (String) 以及 valueOf() 三者的对照关系[java]
    java打印和重写toString
  • 原文地址:https://www.cnblogs.com/liankewei/p/10358828.html
Copyright © 2011-2022 走看看