題目鏈接:點擊查看
題目大意:給出一個無窮個節點的樹,對于每個大于 1 的點 i 來說,可以向點 i / minvid[ i ] 連邊,這里的 mindiv[ x ] 表示的是 x 的最小質因數,現在給定 m 個點分別是 1! , 2! , 3! ... ,每個點都有個權值 w[ i ] ,現在需要找出一個點 u ,使得最小,輸出這個最小值
題目分析:先說收獲,通過這個題讓我稍微明白了一點換根dp。。話說為什么不直接去刷換根dp的題目,感覺有點多此億舉
再說簡單的部分,如果 m 個節點的樹已經求出來了,猜也能猜出來點 u 一定是 m 個點中的一個點,所以我們可以通過樹形dp的換根維護一下最小值就能得到答案了,具體操作如下:
設 dp1[ i ] 為以點 i 為子樹時的點權之和,轉移方程為:dp1[ u ] += dp1[ v ],換根時的轉移方程為:dp1[ u?] -= dp1[ v?] , dp1[ v ] += dp1[ u ]
然后設 dp2[ i ] 為以點 i 為子樹是題目中公式的結果,因為子樹的權值和已經通過 dp1 轉移好了,現在只需要結合距離,也就是深度差就可以轉移 dp2 了,可以想象為?u 的所有子節點 v 所代表的子樹,需要沿著 u - v 這條路徑向上轉移,也就是 dp2[ u ] += dp2[ v ] + ( deep[ v ] - deep[ u ] ) * dp1[ v ] ,當然換根時的轉移方程也是大同小異:dp2[ u ] -= dp2[ v ] + ( deep[ v ] - deep[ u ] ) * dp1[ v ] ,dp2[ v ] += dp2[ u ] +?( deep[ v ] - deep[ u ] ) * dp1[ u?]
注意一下換根時的先后順序,應該先在當前節點 u 中減去子節點 v 的貢獻,然后再在 v 中加上 u 的貢獻
轉移完成后,dp2[ root?] 就是當 u 選為 root 時的答案,為了方便起見,將 root 設為 1 即可
然后就是比較難的虛樹部分了,因為涉及到了階乘,所以原圖中節點的數量會非常龐大,但經過上面的分析,大量的節點都是無用點,只有 1!,2!,3! ... i! ... m! 最多 m 個節點是有用的節點,這樣不難想到虛樹,但因為無法建立原圖,所以不能按照常規的方式構造虛樹,這里需要更加深入了解一下虛樹的構造方法:https://www.cnblogs.com/zwfymqz/p/9175152.html
讀完上面的博客后,我們已經知道,如果想要構造出虛樹,必須要知道的是:
m 個節點的 dfn ( dfs序 ) m 個節點排好序后,所有相鄰節點的 lca 的 dfn
所以此時的關鍵信息就是需要知道,m 個節點的 dfn,下面借用一下zx學長的圖片:
如圖就是含有 1! , 2! , 3! , 4! , 5! , 6! 的一棵樹,省略了很多無用節點
可以通過觀察出的一些結論就是:
對于每一個 i 來說,點 1 到點 i! 的鏈的長度是與 i 呈正相關的關系 還是上面提到的鏈,質因子的大小不增,例如 1 ~ 5! 這條鏈的邊權依次為:5 3 2 2 2 將結論 1 具化一下就是 d[ i + 1 ] = d[ i ] + ( i + 1 的質因子個數 ) 對于 1 ~ i! 這條鏈來說,一定是由 1 ~ ( i - 1?)! 這條鏈加上 i 的質因子繼承過來的,例如 1 ~ 3! 的邊權依次為:3 2,而 1 ~ 4! 的邊權依次為 3 2 2 2,因為 4 的質因子為 2 * 2 ,所以 1 ~ 4! 的邊權在 1 ~ 3! 的基礎上增加了兩個 2 按照上圖構造的樹,點 i! 和點 i 的 dfn 是呈正相關的關系 假如唯一分解?的形式,那么 dis( 1 , i! ) = e1 + e2 + e3 + ... + ek
現在問題就剩下了,如何求兩個點相鄰節點 ( ( i - 1 )! , i! ) 的 lca 的 dfn
上面的第四個結論提到了,1 ~ i! 這條鏈是從?1 ~ ( i - 1 )! 這條鏈繼承而來的,再結合第二個結論,得出?lca( ( i - 1 )! , i! ) 一定是由( i?- 1 )! 和 i! 前面的最大公共質因子組成的一條鏈,而 1 ~ i! 這條鏈相對于 1 ~ ( i - 1 )! 這條鏈多出了 i 的質因子條邊,所以只需要在 1 ~ ( i - 1 )! 這條鏈上找到 i 的最大質因子的位置即可,這樣就能根據第六個結論計算出 dfn[ lca ] 了,可以用線段樹或樹狀數組來實現這個功能,只需要在迭代的同時,利用數據結構維護一下當前 i! 這條鏈上每個質因子的出現次數即可
注意在這個題目中, dfn 和 deep 我都用了 dfn 數組表示,然后 dfn[ i?] 表示的是點 i 的 dfn,而 dfn[ i + n ] 代表的是 lca( ( i - 1 )! , i! ) 的 dfn
代碼: ?
#include<iostream>
#include<cstdio>
#include<string>
#include<ctime>
#include<cmath>
#include<cstring>
#include<algorithm>
#include<stack>
#include<climits>
#include<queue>
#include<map>
#include<set>
#include<sstream>
#include<cassert>
#include<bitset>
using namespace std;typedef long long LL;typedef unsigned long long ull;const int inf=0x3f3f3f3f;const int N=1e6+100;int n,w[N],mindiv[N],c[N],dfn[N],st[N],top;LL dp1[N],dp2[N],ans;vector<int>node[N];int lowbit(int x)
{return x&(-x);
}void add(int pos)
{while(pos<=n){c[pos]++;pos+=lowbit(pos);}
}int ask(int pos)
{int ans=0;while(pos){ans+=c[pos];pos-=lowbit(pos);}return ans;
}void build()
{dfn[1]=1;for(int i=2;i<=n;i++){dfn[i]=dfn[i-1];int j=i;while(j!=mindiv[j])//求出i的最大質因子 j/=mindiv[j];dfn[i+n]=ask(n)-ask(j-1)+1;//dfn[i+n]=dfn[lca((i-1)!,i!)]j=i;while(j!=1)//更新樹狀數組維護的鏈 {dfn[i]++;add(mindiv[j]);j/=mindiv[j];}}int top=0;st[top]=1;for(int i=2;i<=n;i++){int x=i,y=i+n;while(top&&dfn[st[top-1]]>=dfn[y]){node[st[top-1]].push_back(st[top]);top--;}if(dfn[y]!=dfn[st[top]]){node[y].push_back(st[top]);st[top]=y;}st[++top]=x;}while(top){node[st[top-1]].push_back(st[top]);top--;}
}void dfs1(int u)
{dp1[u]=w[u];for(auto v:node[u]){dfs1(v);dp1[u]+=dp1[v];dp2[u]+=dp2[v]+dp1[v]*(dfn[v]-dfn[u]);}
}void dfs2(int u)
{ans=min(ans,dp2[u]);for(auto v:node[u]){LL u1=dp1[u],u2=dp2[u],v1=dp1[v],v2=dp2[v];dp2[u]-=dp2[v]+dp1[v]*(dfn[v]-dfn[u]);dp1[u]-=dp1[v];dp1[v]+=dp1[u];dp2[v]+=dp2[u]+dp1[u]*(dfn[v]-dfn[u]);dfs2(v);dp1[u]=u1,dp2[u]=u2,dp1[v]=v1,dp2[v]=v2;}
}void init(int n)
{ans=1e18;for(int i=0;i<=n<<1;i++){w[i]=c[i]=dp1[i]=dp2[i]=0;node[i].clear();}
}void init()//預處理mindiv[x]:x的最小質因子
{mindiv[1]=1;for(int i=2;i<N;i++)if(!mindiv[i])for(int j=i;j<N;j+=i)if(!mindiv[j])mindiv[j]=i;
}int main()
{
#ifndef ONLINE_JUDGE
// freopen("data.in.txt","r",stdin);
// freopen("data.out.txt","w",stdout);
#endif
// ios::sync_with_stdio(false);init();while(scanf("%d",&n)!=EOF){init((n<<1)+5);for(int i=1;i<=n;i++)scanf("%d",w+i);build();//建虛樹dfs1(1);dfs2(1);printf("%lld\n",ans);}return 0;
}
?
總結
以上是生活随笔 為你收集整理的牛客多校1 - Infinite Tree(虚树+换根dp+树状数组) 的全部內容,希望文章能夠幫你解決所遇到的問題。
如果覺得生活随笔 網站內容還不錯,歡迎將生活随笔 推薦給好友。