联合权值(NOIP2014)奇特的模拟。。

原题传送门

这道题瞄了一眼还以为是SPFA最短路。

后面发现距离为2.。

好像可以枚举中间点来着?

时间效率O(n*(2n-2))≈O(n^2)

BOOM!(PS:9018上过了,说明数据太水了。。)

然后我们看看能不能预处理。。

第一大和第二大可以预处理233~

然后sum(中间点的临近点的权值总和)可以预处理。。。

然后就过了?O(n)

哦,对了忘记讲算法:

最大的联合权值就是中间点的临近点的第一大*第二大。。

所有的联合权值。。

我们假设有三个点a,b,c 那么联合权值=ab+ac+ba+bc+ca+cb=a(b+c)+b(a+c)+c(a+b)=a(sum-a)+b(sum-b)+c(sum-c);

然后就可以O(n)啦!

O(∩_∩)O~~。。

下面先贴O(n^2)代码

#include<iostream>
#include<cstdio>
#include<cstring>
#define mod 10007
using namespace std;
int n,num=0;
struct edge{
    int to,next;
}g[400001];
int head[200001],sum=0;
int w[200001];
void ins(int x1,int y1)
{
    g[++num].next=head[x1];
    head[x1]=num;
    g[num].to=y1;
}
void addedge(int x1,int y1)
{
    ins(x1,y1);
    ins(y1,x1);
}
int main(){
    scanf("%d",&n);
    for(int i=1;i<n;i++)
    {
        int x,y;
        scanf("%d%d",&x,&y);
        addedge(x,y);
    }
    for(int i=1;i<=n;i++)
    scanf("%d",&w[i]);
    int ans1=0,ans2=0;
    for(int i=1;i<=n;i++)
    {
        int max1=-1,max2=-1;
        for(int j=head[i];j;j=g[j].next)
        {
            int tmp=w[g[j].to];
            sum+=tmp;
            sum%=mod;
            if(tmp>max1)
            {
                max2=max1;
                max1=tmp;    
            }
            else if(tmp>max2)
            {
                max2=tmp;
            }
        }
        ans1=max(ans1,max1*max2);
        for(int j=head[i];j;j=g[j].next)
        {
            ans2+=(w[g[j].to]*(sum-w[g[j].to]))%mod;
            ans2%=mod;
        }
        sum=0;
    }
    ans2=(ans2+mod)%mod;
    printf("%d %d
",ans1,ans2);
    return 0;
}

再贴O(N)代码(为啥比上面的还慢。。)

#include<iostream>
#include<cstdio>
#include<cstring>
#define mod 10007
using namespace std;
int n,num=0;
struct edge{
    int to,from;
}g[200001];
int head[200001];
int w[200001];
int max1[200001],max2[200001];
int sum[200001];
void ins(int x1,int y1)
{
    g[++num].to=y1;
    g[num].from=x1;
}
void work(int q,int r){
    if(w[q]>max1[r])
    {
        max2[r]=max1[r];
        max1[r]=w[q];    
    }
    else if(w[q]>max2[r]) max2[r]=w[q];    
}
int main(){
    scanf("%d",&n);
    for(int i=1;i<n;i++)
    {
        int x,y;
        scanf("%d%d",&x,&y);
        ins(x,y);
    }
    for(int i=1;i<=n;i++)
    scanf("%d",&w[i]);
    int ans1=0,ans2=0;
    for(int i=1;i<n;i++)
    {
        int u=g[i].from,v=g[i].to;
        sum[u]=(sum[u]+w[v])%mod;
        sum[v]=(sum[v]+w[u])%mod;
        work(u,v);
        work(v,u);
    }

    for(int i=1;i<=n;i++)ans1=max(ans1,max1[i]*max2[i]);
    for(int i=1;i<n;i++)
    {
        int u=g[i].from,v=g[i].to;
        ans2+=(w[u]*(sum[v]-w[u]))%mod;
        ans2%=mod;
        ans2+=(w[v]*(sum[u]-w[v]))%mod;
        ans2%=mod;
    }
    ans2=(ans2+mod)%mod;
    printf("%d %d
",ans1,ans2);
    return 0;
}
原文地址:https://www.cnblogs.com/ghostfly233/p/6855279.html