hdu多校第九場 1005(hdu-6430:TeaTree)

 

題目大意:

對於一個結點 x,它的值可以是當前子樹內任意兩點的gcd值。但是要求 lca(i,j)=x。

最後問你每個結點最大的值可能是多少,如果不存在輸出-1。

 

解題思路:

本來想用樹上dsu來寫的,結果寫了一上午,總感覺dsu有哪些地方不對勁,開始刪刪改改,最後發現寫出來了一個暴力合併,複雜度的話不太會證明,可能因爲約數較少的緣故,所以複雜度不是很高。

具體實現就是預先打出每個結點的約數,用vector保存起來。保存以後直接dfs,對於當前結點,把它的所有兒子遍歷完之後,我們使用一個bitset把當前結點的約數加入bitset中,之後對於它的每個兒子結點,我們在bitset中查詢是否存在 對於已經存在的數取max,不存在的話加入bitset 同時加入當前結點的約數表,這樣保證我們每次查詢的時候都只需要往下查詢一層即可。

 

其實這個做法我後來想想還是能用dsu來優化一部分的,例如我們可以把重兒子的bitset不清空,那麼重兒子的bitset就可以加以利用,但是其實我的做法需要把兒子結點的約數表合併到父親結點,那麼還是要遍歷重兒子的約數表,那麼預先儲存的bitset感覺優化就不大了,但是其實也有解決的辦法,就是可以先把其他結點的約數合併到重兒子中,最後直接賦值給父親結點即可。不知道能優化多少,我也不想去寫了= = 

Ac代碼:

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn=1e5+5;
const int mod=1e9+7;
const int INF=1e9+7;
ll powmod(ll a,ll b) {ll res=1;a%=mod; assert(b>=0); for(;b;b>>=1){if(b&1)res=res*a%mod;a=a*a%mod;}return res;}
ll gcd(ll a,ll b) { return b?gcd(b,a%b):a;}
int n,tmp,ans[maxn];
vector<int> rv[maxn],val[maxn],v[maxn]; //rv保存每個數約數 val保存每個結點約數 v建圖
bitset<maxn> vs;
void unite(int x,int y) //將y結點合併進x結點
{
    for(int i=0;i<val[y].size();i++)
    {
        if(vs.test(val[y][i])) tmp=max(tmp,val[y][i]);  //如果bitset中已經存在取max
        else val[x].push_back(val[y][i]),vs.set(val[y][i]); //不存在則加入bitset以及x的約數表
    }
}
void dfs(int x,int fa)
{
    for(int i=0;i<v[x].size();i++)
    {
        int u=v[x][i];
        if(u==fa) continue;
        dfs(u,x);
    }
    tmp=-1;
    for(int i=0;i<val[x].size();i++) vs.set(val[x][i]); //預先將當前結點約數加入bitset
    for(int i=0;i<v[x].size();i++)  //將所有兒子結點的約數加入bitset
    {
        int u=v[x][i];
        if(u==fa) continue;
        unite(x,u);
    }
    ans[x]=tmp;
    vs.reset(); //清空bitset
}
int main()
{
    for(int i=1;i<maxn;i++) //打約數表
    {   
        for(int j=1;j<maxn;j++)
        {
            if(i*j>maxn) break;
            rv[i*j].push_back(i);
        }
    }
    scanf("%d",&n);
    for(int i=2;i<=n;i++)
    {
        int x; scanf("%d",&x);
        v[i].push_back(x);
        v[x].push_back(i);
    }
    for(int i=1;i<=n;i++)   //得到每個結點的約數表
    {
        int x; scanf("%d",&x);
        val[i]=rv[x];
    }
    dfs(1,0);
    for(int i=1;i<=n;i++) printf("%d\n",ans[i]);
    //system("pause");
}

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章