洛谷P1351 联合权值(NOIp2014)

来源:互联网 发布:李成儒饰演淘宝电视剧 编辑:程序博客网 时间:2024/06/06 03:15

技巧题

题目传送门

题目意思很简单,求两个距离为2的点的点权。可以转化为求一个点其中两条出边的点权。

刚开始写DFS,然后华丽丽地T掉了。。。以为哪里写挂了,算了一下发现是O(n2)的。。。于是重新想算法

后来发现一个公式:2(a[1]a[2]+a[2]a[3]+a[1]a[3])=(a[1]+a[2]+a[3])2(a[1]2+a[2]2+a[3]2)
它的拓展式也是成立的。(证明的话展开化简即可)

于是我们只需要遍历一遍就行了,算值的时候把这个东西代进去。求最大值就是求前二大值的积。

代码:

#include<cstdio>#include<cstring>#include<algorithm>#define MAXN 200000#define DALAO 10007using namespace std;typedef long long LL;struct edge{    int next,to;};int n,k;LL sum,ans;int h[MAXN+5],w[MAXN+5];edge ed[MAXN*2+5];inline char readc(){    static char buf[100000],*l=buf,*r=buf;    if (l==r) r=(l=buf)+fread(buf,1,100000,stdin);    if (l==r) return EOF; return *l++;}inline int _read(){    int num=0; char ch=readc();    while (ch<'0'||ch>'9') ch=readc();    while (ch>='0'&&ch<='9') { num=num*10+ch-48; ch=readc(); }    return num;}void addedge(int x,int y){    ed[++k].next=h[x]; ed[k].to=y; h[x]=k;}void calc(int x){    LL s1=0,s2=0,t1=0,t2=0;    for (int i=h[x];i;i=ed[i].next){        int v=ed[i].to;        s1+=w[v]; s2+=w[v]*w[v];        if (t1<w[v]) t1=w[v];        else if (w[v]>t2) t2=w[v];    }    s1*=s1; ans=max(ans,t1*t2); sum=(((s1-s2)%DALAO+sum)%DALAO)%DALAO;}int main(){    n=_read();    for (int i=1;i<n;i++){        int u=_read(),v=_read();        addedge(u,v); addedge(v,u);    }    for (int i=1;i<=n;i++) w[i]=_read();    for (int i=1;i<=n;i++) calc(i);    printf("%lld %lld\n",ans,sum%DALAO);//其实并不需要long long    return 0;}
原创粉丝点击