codevs 3728 联合权值

/*
一开始的思路 求出每两个点之间的距离(其实枚举两个点就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\n",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\n",ans,sum);
    return 0;
} 
时间: 2024-10-09 05:23:37

codevs 3728 联合权值的相关文章

codevs3728联合权值(LCA)

3728 联合权值 时间限制: 1 s 空间限制: 128000 KB 题目等级 : 黄金 Gold 题解 查看运行结果 题目描述 Description 输入描述 Input Description 输出描述 Output Description 样例输入 Sample Input 样例输出 Sample Output 数据范围及提示 Data Size & Hint /* 自己打暴力,看了看不用打LCA只处理倍增数组 然后就10分了...... 神奇的LCA 估计打了能有60分 只能看峰峰.

联合权值(codevs 3728)

Description 无向连通图 G 有 n 个点,n−1 条边.点从 1 到 n 依次编号,编号为 i 的点的权值为 Wi,每条边的长度均为 1.图上两点 (u,v) 的距离定义为 u 点到 v 点的最短距离.对于图 G 上的点对 (u,v),若它们的距离为 2,则它们之间会产生Wv×Wu 的联合权值. 请问图 G 上所有可产生联合权值的有序点对中,联合权值最大的是多少?所有联合权值之和是多少? Input Format 第一行包含 1 个整数 n. 接下来 n−1 行,每行包含 2 个用空

[NOIP2014]联合权值

描述 无向连通图G有n个点,n-1条边.点从1到n依次编号,编号为i的点的权值为Wi  ,每条边的长度均为1.图上两点(u, v)的距离定义为u点到v点的最短距离.对于图G上的点对(u, v),若它们的距离为2,则它们之间会产生Wu×Wv的联合权值. 请问图G上所有可产生联合权值的有序点对中,联合权值最大的是多少?所有联合权值之和是多少? 输入格式 输入文件名为link.in. 第一行包含1个整数n. 接下来n-1行,每行包含2个用空格隔开的正整数u.v,表示编号为u和编号为v的点之间有边相连.

洛谷 P1351 联合权值(NOIp2014D1T2)

题目描述 无向连通图G 有n 个点,n - 1 条边.点从1 到n 依次编号,编号为 i 的点的权值为W i ,每条边的长度均为1 .图上两点( u , v ) 的距离定义为u 点到v 点的最短距离.对于图G 上的点对( u, v) ,若它们的距离为2 ,则它们之间会产生Wu×Wv 的联合权值. 请问图G 上所有可产生联合权值的有序点对中,联合权值最大的是多少?所有联合权值之和是多少? 输入输出格式 输入格式: 输入文件名为link .in. 第一行包含1 个整数n . 接下来n - 1 行,每

洛谷——P1351 联合权值

https://www.luogu.org/problem/show?pid=1351 题目描述 无向连通图G 有n 个点,n - 1 条边.点从1 到n 依次编号,编号为 i 的点的权值为W i ,每条边的长度均为1 .图上两点( u , v ) 的距离定义为u 点到v 点的最短距离.对于图G 上的点对( u, v) ,若它们的距离为2 ,则它们之间会产生Wu×Wv 的联合权值. 请问图G 上所有可产生联合权值的有序点对中,联合权值最大的是多少?所有联合权值之和是多少? 输入输出格式 输入格式

洛谷【P1351】codevs3728 联合权值

题目描述 无向连通图G 有n 个点,n - 1 条边.点从1 到n 依次编号,编号为 i 的点的权值为W i ,每条边的长度均为1 .图上两点( u , v ) 的距离定义为u 点到v 点的最短距离.对于图G 上的点对( u, v) ,若它们的距离为2 ,则它们之间会产生Wu×Wv 的联合权值. 请问图G 上所有可产生联合权值的有序点对中,联合权值最大的是多少?所有联合权值之和是多少? 输入输出格式 输入格式: 输入文件名为link .in. 第一行包含1 个整数n . 接下来n - 1 行,每

【NOIP之旅】NOIP2014 day1 T2 联合权值

2.联合权值 (link.cpp/c/pas) [问题描述] 无向连通图G有n个点,n-1条边.点从1到n依次编号,编号为i的点的权值为Wi  ,每条边的长度均为1.图上两点(u, v)的距离定义为u点到v点的最短距离.对于图G上的点对(u, v),若它们的距离为2,则它们之间会产生Wu×Wv的联合权值. 请问图G上所有可产生联合权值的有序点对中,联合权值最大的是多少?所有联合权值之和是多少? [输入] 输入文件名为link.in. 第一行包含1个整数n. 接下来n-1行,每行包含2个用空格隔开

洛谷1351 联合权值

题目描述 无向连通图G 有n 个点,n - 1 条边.点从1 到n 依次编号,编号为 i 的点的权值为W i   ,每条边的长度均为1 .图上两点( u ,  v ) 的距离定义为u 点到v 点的最短距离.对于图G 上的点对( u, v) ,若它们的距离为2 ,则它们之间会产生Wu×Wv 的联合权值. 请问图G 上所有可产生联合权值的有序点对中,联合权值最大的是多少?所有联合权值之和是多少? 输入输出格式 输入格式: 输入文件名为link .in. 第一行包含1 个整数n . 接下来n - 1

NOIP 2014 D1T2 -联合权值

联合权值 (link.cpp/c/pas) [问题描述] 无向连通图G有n个点,n-1条边.点从1到n依次编号,编号为i的点的权值为Wi  ,每条边的长度均为1.图上两点(u, v)的距离定义为u点到v点的最短距离.对于图G上的点对(u, v),若它们的距离为2,则它们之间会产生Wu×Wv的联合权值. 请问图G上所有可产生联合权值的有序点对中,联合权值最大的是多少?所有联合权值之和是多少? [输入] 输入文件名为link.in. 第一行包含1个整数n. 接下来n-1行,每行包含2个用空格隔开的正