COGS 2084. Asm.Def的基本算法

★☆   输入文件:asm_algo.in   输出文件:asm_algo.out   简单对比
时间限制:1 s   内存限制:256 MB

【题目描述】

“有句美国俗语说,如果走起来像鸭子,叫起来像鸭子,那就是一只鸭子。”斯科特·华莱士看着Asm.Def面前屏幕上滚动的绿色字符,若有所思地说。

“什么意思?”

“你的数据。看上去是一棵树。”

“按照保密条令,我什么也不说这是最好的——但见你这么热情,一句话不说也不好。”Asm.Def停下手中的快速数论变换,“确实是树。”

“然后你怎么算出来目标的位置?”

“都需要按照基本算法,按照图论的那一套理论,去产生。听说过LCA吗?不是那个印度飞机,我是说最近公共祖先……”

Asm.Def通过分析无线电信号得到了一棵有n个节点,以1为根的树。除1之外,节点i的父亲是p_i。节点带有权值,节点i的权值是w_i。

我们定义某点的祖先为从根到它路径上的所有点(包括它本身),而两个节点a、b的最近公共祖先是某个点p,使得p同时是a、b的祖先,而且p离根最远。

Asm.Def想要求出

(文字:∑∑w_i*w_j*w_LCA(i,j)),

其中LCA(i,j)是i、j的最近公共祖先,他认为这个值至关重要。由于这个值可能很大,Asm.Def只需要知道它模1,000,000,007(即10^9+7)的结果。

【输入格式】

第1行两个整数:n和w_1.

第2行到第n行,第i行有两个整数p_i和w_i。

【输出格式】

一行一个整数,即答案模1,000,000,007的值。

【样例输入】

2 2
1 1

【样例输出】

17

【提示】

1×1×1+1×2×2+2×1×2+2×2×2=17。

对于30%的数据,n<=100,w_i<=10。

对于60%的数据,n<=1000,w_i<=1000.

对于100%的数据,1<=n<=10^5,0<=w_i<=10^9,1<=p_i<i.

【来源】

在此键入。

Tarjan法求lca我认为是可以过的 

但是需要的数组开不下 数组需要 100000*99999/2 这么大 三个 

开不下 

屠龙宝刀点击就送

#include <ctype.h>
#include <cstdio>
#include <vector>
#define mod 1000000007
#define N 150000
using namespace std;
vector<int>edge[N];
vector<int>q[N];
inline void read(int &x)
{
    register char ch=getchar();
    for(x=0;!isdigit(ch);ch=getchar());
    for(;isdigit(ch);ch=getchar()) x=x*10+ch-'0';
}
int y,Answer,u[N<<2],v[N<<2],ans[N<<2],num,n,dep[N],fa[N],dad[N],w[N];
int find_(int x) {return x==fa[x]?x:fa[x]=find_(fa[x]);}
void dfs(int x)
{
    fa[x]=x;
    for(int i=0;i<edge[x].size();i++)
    if(dad[x]!=edge[x][i]) dad[edge[x][i]]=x,dfs(edge[x][i]);
    for(int i=0;i<q[x].size();i++)
    if(dad[y=u[q[x][i]]^v[q[x][i]]^x]) ans[q[x][i]]=(w[find_(y)]*2)%mod;
    fa[x]=dad[x];
}
int main()
{
    freopen("asm_algo.in","r",stdin);
    freopen("asm_algo.out","w",stdout);
    read(n);
    read(w[1]);
    Answer=(Answer%mod+((w[1]%mod)*(w[1]%mod)*(w[1]%mod)%mod))%mod;
    for(int p,i=2;i<=n;i++)
    {
        read(p);
        read(w[i]);
        Answer=(Answer%mod+((w[i]%mod)*(w[i]%mod)*(w[i]%mod)%mod))%mod;
        edge[i].push_back(p);
        edge[p].push_back(i);
    }
    for(int i=1;i<=n;i++)
    {
        for(int j=1;j<i;j++)
        {
            u[++num]=i;
            v[num]=j;
            q[u[num]].push_back(num);
            q[v[num]].push_back(num);  
        }
    }
    dfs(1);
    for(int i=1;i<=num;i++) Answer=(Answer%mod+((ans[i]%mod)*(w[u[i]]%mod)*(w[v[i]]%mod)%mod))%mod;
    printf("%d
",Answer);
    return 0;
}
TarjanLCA
#include <ctype.h>
#include <cstdio>
#include <vector>
#define mod 1000000007
#define N 200005
using namespace std;
typedef long long LL;
vector<LL>edge[N];

inline void read(LL &x)
{
    register char ch=getchar();
    for(x=0;!isdigit(ch);ch=getchar());
    for(;isdigit(ch);ch=getchar()) x=x*10+ch-'0';
}
LL sum[N],ans,n,w[N],siz[N],dep[N],dad[N],top[N];
void dfs(LL x)
{
    sum[x]=w[x];
    for(LL i=0;i<edge[x].size();++i)
    {
        LL v=edge[x][i];
        if(dad[x]!=v)
        {
            dad[v]=x;
            dfs(v);
            ans=(ans%mod+sum[x]%mod*sum[v]%mod*w[x]%mod)%mod;
            sum[x]=(sum[x]%mod+sum[v]%mod)%mod;
        }
    }
}
int main()
{
    freopen("asm_algo.in","r",stdin);
    freopen("asm_algo.out","w",stdout);
    read(n);
    read(w[1]);
    for(LL p,i=2;i<=n;++i)
    {
        read(p);
        read(w[i]);
        edge[p].push_back(i); 
        edge[i].push_back(p); 
    }
    dfs(1);
    ans=ans%mod*2%mod;
    for(int i=1;i<=n;++i) ans=(ans%mod+w[i]%mod*w[i]%mod*w[i]%mod)%mod;
    printf("%lld
",ans%mod);
    return 0;
}
我们都在命运之湖上荡舟划桨,波浪起伏着而我们无法逃脱孤航。但是假使我们迷失了方向,波浪将指引我们穿越另一天的曙光。
原文地址:https://www.cnblogs.com/ruojisun/p/7382275.html