zoukankan      html  css  js  c++  java
  • codevs3728联合权值(LCA)

    3728 联合权值

     

     时间限制: 1 s
     空间限制: 128000 KB
     题目等级 : 黄金 Gold
     
     
    题目描述 Description

    输入描述 Input Description

    输出描述 Output Description

    blob.png

    样例输入 Sample Input

    样例输出 Sample Output

    数据范围及提示 Data Size & Hint

    /*
    自己打暴力,看了看不用打LCA只处理倍增数组
    然后就10分了......
    神奇的LCA 估计打了能有60分 
    只能看峰峰... 
    */
    
    #include<iostream>
    #include<cstdio>
    #include<cstdlib>
    #define maxn 200001
    #define mod 10007
    
    using namespace std;
    int n,m,cnt,ans,num,tot,x,y,z,maxx;
    int head[maxn],deep[maxn],dis[maxn];
    int f[maxn][20]; 
    struct node
    {
        int from;
        int to;
        int dis;
        int next;
    }e[maxn*2];
    
    int init()
    {
        int x=0,f=1;char c=getchar();
        while(c>'9'||c<'0'){if(c=='-')f=-1;c=getchar();}
        while(c>='0'&&c<='9'){x=x*10+c-'0';c=getchar();}
        return x*f;
    }
    
    void add(int from,int to)
    {
        e[++num].from=from;
        e[num].to=to;
        e[num].next=head[from];
        head[from]=num;
    }
    
    void get_fa()
    {
        for(int j=1;j<=20;j++)
          for(int i=1;i<=n;i++)
            f[i][j]=f[f[i][j-1]][j-1];
    }
    
    void Dfs(int from,int now,int cnt)
    {
        f[now][0]=from;deep[now]=cnt;
        for(int i=head[now];i;i=e[i].next)
        {
            int v=e[i].to;
            if(v!=from)
              Dfs(now,v,cnt+1);
        }
    }
    
    int main()
    {
        n=init();
        for(int i=1;i<n;i++)
        {
            x=init();y=init();
            add(x,y);add(y,x);
        }
        for(int i=1;i<=n;i++)
          dis[i]=init();
        Dfs(1,1,0);
        get_fa();
        for(int i=1;i<=n;i++)
          for(int j=1;j<=n;j++)
            {
                if(j==i) continue;
                {
                    if(deep[i]==deep[j]&&f[i][0]==f[j][0]||deep[i]-deep[j]==2&&f[i][1]==j||deep[j]-deep[i]==2&&f[j][1]==i)
                      {
                           tot+=dis[i]*dis[j];
                           maxx=max(maxx,dis[i]*dis[j]);
                      }
                }
            }
        printf("%d %d
    ",maxx,tot%mod);
    }
    /*
    峰峰果然是大神 果然裸地LCA枚举60分
    开始的思路 求出每两个点之间的距离(其实枚举两个点就T了) 统计为2 的点对 然后统计答案 倍增LCA的话 是O(n+n*n) 后面的n*n是枚举那两个点 T了 60分 */ #include<iostream> #include<cstdio> #include<cstring> #define maxn 200010 using namespace std; int n,w[maxn],fa[maxn][20],head[maxn],num,dep[maxn],ans,sum; struct node { int u,v,pre; }e[maxn*2]; int init() { int x=0;char s=getchar(); while(s<'0'||s>'9')s=getchar(); while(s>='0'&&s<='9'){x=x*10+s-'0';s=getchar();} return x; } void Add(int from,int to) { num++; e[num].u=from; e[num].v=to; e[num].pre=head[from]; head[from]=num; } void Dfs(int now,int from,int c) { fa[now][0]=from; dep[now]=c; for(int i=head[now];i;i=e[i].pre) if(e[i].v!=from) Dfs(e[i].v,now,c+1); } void Get_fa() { for(int j=1;j<=17;j++) for(int i=1;i<=n;i++) fa[i][j]=fa[fa[i][j-1]][j-1]; } int Get_a(int a,int t) { for(int i=1;i<=t;i++) a=fa[a][0]; return a; } int LCA(int a,int b) { if(dep[a]<dep[b])swap(a,b); a=Get_a(a,dep[a]-dep[b]); if(a==b)return a; for(int i=17;i>=0;i--) if(fa[a][i]!=fa[b][i]) { a=fa[a][i]; b=fa[b][i]; } return fa[a][0]; } int main() { //freopen("linkb.in","r",stdin); //freopen("linkb.out","w",stdout); n=init(); int u,v; for(int i=1;i<=n-1;i++) { u=init();v=init(); Add(u,v);Add(v,u); } for(int i=1;i<=n;i++) w[i]=init(); Dfs(1,1,0); Get_fa(); for(int i=1;i<=n;i++) for(int j=i+1;j<=n;j++) { int anc=LCA(i,j); int deep=dep[i]+dep[j]-2*dep[anc]; if(deep==2) { ans=max(ans,w[i]*w[j]); sum=(sum+w[i]*w[j])%10007; } } printf("%d %d ",ans,sum*2%10007); return 0; }
    /*
    因为默认的边权值是1 所以距离为2的点也就是从同一个点出发的两个
    这样我们不需要n*n的枚举点 我们统计每个点之间相连的
    然后两两组合 这里会发现 又跑慢了 70分
    假设点x直接相连的点有三个 权值分别是a b c
    那么我们两两组合后总权值是ab+bc+ac
    会发现这里和之前用线段树求区间两两元素之和是一样的
    根据数学公式 (a+b+c)^2-a^2-b^2-c^2=2*(ab+bc+ac)
    这样我们就可以很快地求出权值和 至于最大的嘛 那肯定是最大的两个点权之积 
    */
    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #define maxn 200010
    #define mod 10007
    using namespace std;
    int n,w[maxn],head[maxn],num,ans,sum;
    struct node
    {
        int u,v,pre;
    }e[maxn*2];
    int cmp(int x,int y)
    {
        return x>y;
    }
    int init()
    {
        int x=0;char s=getchar();
        while(s<'0'||s>'9')s=getchar();
        while(s>='0'&&s<='9'){x=x*10+s-'0';s=getchar();}
        return x;
    }
    void Add(int from,int to)
    {
        num++;
        e[num].u=from;
        e[num].v=to;
        e[num].pre=head[from];
        head[from]=num;
    }
    int main()
    {
        //freopen("linkb.in","r",stdin);
        //freopen("linkb.out","w",stdout);
        n=init();
        int x,y;
        for(int i=1;i<=n-1;i++)
          {
              x=init();y=init();
              Add(x,y);Add(y,x);
          }
        for(int i=1;i<=n;i++)
          w[i]=init();
        for(int u=1;u<=n;u++)
          {
              int p[maxn],l=0,tmp=0,s=0;
            for(int i=head[u];i;i=e[i].pre)
              p[++l]=w[e[i].v];
            sort(p+1,p+1+l,cmp);
            ans=max(ans,p[1]*p[2]);
            for(int i=1;i<=l;i++)
              {
                tmp=(tmp+p[i]*p[i]%mod)%mod;
                s=(s+p[i]%mod)%mod;
              }
            sum=(sum+(s*s-tmp)%mod)%mod;
          }
        printf("%d %d
    ",ans,sum);
        return 0;
    }
    折花枝,恨花枝,准拟花开人共卮,开时人去时。 怕相思,已相思,轮到相思没处辞,眉间露一丝。
  • 相关阅读:
    [USACO07DEC]观光奶牛Sightseeing Cows
    洛谷 U3348 A2-回文数
    LOJ #2037. 「SHOI2015」脑洞治疗仪
    1441 士兵的数字游戏
    BZOJ 1108: [POI2007]天然气管道Gaz
    P3047 [USACO12FEB]附近的牛Nearby Cows
    POJ 3061 Subsequence
    Hdu 5776 sum
    1052 最大M子段和
    1288 埃及分数
  • 原文地址:https://www.cnblogs.com/L-Memory/p/6366984.html
Copyright © 2011-2022 走看看