2084. Asm.Def的基本算法

2084. Asm.Def的基本算法

傳送門php

★☆   輸入文件: asm_algo.in   輸出文件: asm_algo.out   簡單對比
時間限制:1 s   內存限制:256 MB

【題目描述】

 

「有句美國俗語說,若是走起來像鴨子,叫起來像鴨子,那就是一隻鴨子。」斯科特·華萊士看着Asm.Def面前屏幕上滾動的綠色字符,如有所思地說。 ios

「什麼意思?」 算法

「你的數據。看上去是一棵樹。」 spa

「按照保密條令,我什麼也不說這是最好的——但見你這麼熱情,一句話不說也很差。」Asm.Def停下手中的快速數論變換,「確實是樹。」 code

「而後你怎麼算出來目標的位置?」 blog

「都須要按照基本算法,按照圖論的那一套理論,去產生。據說過LCA嗎?不是那個印度飛機,我是說最近公共祖先……」 內存

Asm.Def經過分析無線電信號獲得了一棵有n個節點,以1爲根的樹。除1以外,節點i的父親是p_i。節點帶有權值,節點i的權值是w_i。 get

咱們定義某點的祖先爲從根到它路徑上的全部點(包括它自己),而兩個節點a、b的最近公共祖先是某個點p,使得p同時是a、b的祖先,並且p離根最遠。 it

Asm.Def想要求出 io

(文字:∑∑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.

 【超時code】

dalao說沒事先打暴力,說不定會想出思路,然而並無。超時4個點。

用define定義的mod一直錯 輸出1e009...

而後建邊時沒有建雙邊....

樹剖寫錯.....

#include<iostream>
#include<cstdio>
#include<vector>
#include<algorithm>
using namespace std;
//#define mod 1e9
const int mod=1e9+7;
int w[100008],dad[100008],size[100008],top[100008],deep[100008];
long long ans;
int n,da;
vector<int>vec[100008];
void dfs1(int x) {
    size[x]=1;
    deep[x]=deep[dad[x]]+1;
    for(int i=0; i<vec[x].size(); i++) {
        if(dad[x]!=vec[x][i]) {
            dad[vec[x][i]]=x;
            dfs1(vec[x][i]);
            size[x]+=size[vec[x][i]];
        }
    }
}
void dfs2(int x) {
    if(!top[x])top[x]=x;
    int t=0;
    for(int i=0; i<vec[x].size(); i++) {
        if(dad[x]!=vec[x][i]&&size[vec[x][i]]>size[t])
            t=vec[x][i];
    }
    if(t) {
//    top[t]=x;
        top[t]=top[x];
        dfs2(t);
    }
    for(int i=0; i<vec[x].size(); i++) {
        if(dad[x]!=vec[x][i]&&vec[x][i]!=t)
            dfs2(vec[x][i]);
    }
}
int lca(int x,int y) {
    for(; top[x]!=top[y];) {
        if(deep[x]<deep[y])
            swap(x,y);
//    top[x]=dad[top[x]];
        x=dad[top[x]];
    }
    if(deep[x]<deep[y])return x;
    return y;
}
int main() {
    freopen("asm_algo.in","r",stdin);
    freopen("asm_algo.out","w",stdout);
    scanf("%d%d",&n,&w[1]);
    for(int i=2; i<=n; i++) {
        scanf("%d%d",&da,&w[i]);
        vec[da].push_back(i);
        vec[i].push_back(da);//建雙向邊
    }
    dfs1(1);
    dfs2(1);
    for(int i=1; i<=n; i++)
        for(int j=1; j<=n; j++)
            ans=(ans+w[i]*w[j]*w[lca(i,j)])%mod;
    cout<<ans<<endl;
    return 0;
}

【AC code】

一氣之下全改爲long long 就過了。

【思路】

如圖的矩陣表示i,j的lca。發現對角線兩側是對稱的(由於i,j的lca==j,i的lca);

那麼咱們只要求出對角線的一側的值再*2+對角線上的值就是答案。

#include<iostream>
#include<cstdio>
using namespace std;
const int mod=1e9+7;
const int maxx=1e5;
struct Edge
{
    long long  x,y,next;
    Edge(int x=0,int y=0,int next=0):
        x(x),y(y),next(next){}
}edge[maxx<<1];
long long  head[maxx+1],w[maxx+1],sum[maxx+1],dad[maxx+1];
long long n,sumedge,da;
long long ans;
void add(int x,int y)
{
    edge[++sumedge]=Edge(x,y,head[x]);
    head[x]=sumedge;
}
void dfs(int x)
{
    sum[x]=w[x];
    for(long long  i=head[x];i;i=edge[i].next)
    {
        if(!dad[edge[i].y])
        {
            dad[edge[i].y]=x;dfs(edge[i].y);
            ans=(ans%mod+sum[x]%mod*sum[edge[i].y]%mod*w[x]%mod)%mod;
            sum[x]=(sum[x]%mod+sum[edge[i].y]%mod)%mod;
        }
    }
}
int main()
{
    freopen("asm_algo.in","r",stdin);
    freopen("asm_algo.out","w",stdout);
    scanf("%lld%lld",&n,&w[1]);
    for(long long i=2;i<=n;i++)
    {
        scanf("%d%d",&da,w+i);//not &w+i;
        add(da,i);
    }
    dfs(1);
    ans=ans*2%mod;
    for(long long i=1;i<=n;i++)
    ans=(ans%mod+w[i]%mod*w[i]%mod*w[i]%mod)%mod;
    printf("%lld\n",ans%mod);
    return 0;
}
相關文章
相關標籤/搜索