日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

Fantasia (Tarjan+树形DP)

發布時間:2023/12/20 编程问答 36 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Fantasia (Tarjan+树形DP) 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

??

Time Limit:?1000 ms???Memory Limit:?256 MB

Description

  給定一張N個點、M條邊的無向圖 $G$ 。每個點有個權值Wi。

  我們定義 $G_i$ 為圖 $G$ 中刪除第 $i$ 號頂點后的圖。我們想計算 $G_1, G_2, ..., G_n$ 這N張圖的權值。

  對于任意一張圖 $G$ ,它的權值是這樣定義的:

  1. 如果 $G$ 是聯通圖,那么 $G$ 的權值為 $G$ 中所有頂點權值的乘積。

  2. 如果 $G$ 是非聯通圖,那么 $G$ 的權值為 $G$ 中所有聯通塊的權值之和。

  $G$ 中的一個聯通塊指的是 $G$ 的一個子圖,并且這個子圖中的點兩兩相連(包括直接連接或者間接連接),并且不存在子圖外的點使得子圖內的點能與子圖外的點相連。

Input

  第一行包含兩個整數 $n$ 和 $m$ $(2 \le n \le 10^5, 1 \le m \le 2 \times 10^5)$ ,分別表示點數和邊數。

  第二行包含 $n$ 個整數 $w_1, w_2, ..., w_n$ $(1 \le w_i \le 10^9)$, 表示每個頂點的權值。

  接下來 m 行,每行兩個整數 $x_i$ 和 $y_i$ $(1 \le x_i, y_i \le n, x_i \ne y_i)$, 表示一條無向邊。

  輸出只有一個整數: $S = (\sum\limits_{i=1}^{n}i\cdot z_i) \text{ mod } (10^9 + 7)$, 其中 $z_i$ 是圖 $G_i$ 的權值。

?

Sample Input

Sample Output

10 3 3 3 3 2 3 3 2 3 1 3 1 1 3 1 2 1 3 1 1 1 2 1 2 2 1 3 2 1 2 1 3 1 3 0 1 0 1 0 0 1

?

?

Hint?

  【數據范圍及約定】

  子任務1(5分): $n \leq 10, m \leq 20$

  子任務2(10分): $n \leq 1000, m \leq 2000$

  子任務3(20分): 該圖恰為一棵樹,$m = n-1$

  子任務4(20分): 該圖為一幅聯通圖

  子任務5(45分): 我們會拿最強的數據來評測你的程序(mmp)

  對于所有數據,$2 \le n \le 10^5, 1 \le m \le 2 \times 10^5$

?


?

題解

  沒有什么能阻擋我把Tarjan打殘。

  題目涉及到刪點操作。

  如果刪的點$u$是一個非割頂,那么它的消失貌似對這個聯通塊整體沒有太大的影響,要處理的話僅僅是該當前聯通塊的權值$val$除去$u$的權值$w_u$。

  如果刪的點$u$是一個割頂,那么它會將這個聯通塊分成若干部分,具體就是在Tarjan的縮點樹上,把子樹全部斷開,把父親也斷開。問題來了,割頂這個東西很煩怎么處理?

 

轉樹

  割頂出現了!它可以同時處于多個點雙內,mmp

  對于每個點雙,我們暫且新建一個代表點,將點雙內的所有點連向這個代表點。這樣,一個割頂可以被連接到多個點雙的代表點,同時整個圖轉成了樹的形態。

  

  那么斷開一個割頂$u$會影響到哪些區塊,就一目了然了,即這種樹上,$u$的所有子樹和父親那一頭的部分。

  發現這其實同化了斷開非割頂的操作,非割頂永遠處于根節點或葉子節點,其實本質上處理是一樣的。

  維護

  $$f_u=\prod\limits_{v\in 以u為根的樹}w[v]\\g_u=\sum\limits_{v是u的子樹}f[v]$$

  則刪去一個點$u$,對所在聯通塊權值$val$的影響即為:

  $$val=\frac{val}{f_u}+g_u$$

 ? ?即父親那一頭的權值+所有子樹的權值和

?

小細節與特判

  1.處理刪去割頂的時候(即上面的最后一個公式),$\frac{val}{f_u}$希望得到的是父親那一頭的權值,但如果$u$是樹的根,這玩意弄出來卻是1,而不是我們希望的0(坑爹),所以記錄一下我們要處理的割頂是不是一個樹的根,特判一下。

 ? ?2.Tarjan深搜的起始點要記為割頂。

?


?

1 #include <cstdio> 2 #define min(a,b) (a<b?a:b) 3 using namespace std; 4 typedef long long ll; 5 const ll N=200010,Mod=1e9+7; 6 int n,m,h1[N],h2[N*2],tot; 7 int col[N],colcnt,st[N],top,bcnt,head[N]; 8 ll info[N],sumup,ans,f[N*2],g[N*2],w[N*2]; 9 int dfn[N],low[N],ins[N],tmcnt; 10 bool cut[N]; 11 struct Edge{int v,next;}G[N*6]; 12 inline void addEdge(int u,int v,int *h){ 13 G[++tot].v=v; G[tot].next=h[u]; h[u]=tot; 14 } 15 void tarjan(int u,int fa){ 16 st[++top]=u; 17 ins[u]=1; 18 dfn[u]=low[u]=++tmcnt; 19 col[u]=colcnt; 20 info[col[u]]=(info[col[u]]*w[u])%Mod; 21 for(int i=h1[u],v,ccnt=0;i;i=G[i].next) 22 if((v=G[i].v)!=fa){ 23 if(!ins[v]){ 24 ccnt++; 25 tarjan(v,u); 26 low[u]=min(low[u],low[v]); 27 if((!fa&&ccnt>1)||(fa&&dfn[u]<=low[v])) 28 cut[u]=1; 29 if(dfn[u]<=low[v]){ 30 w[(++bcnt)+n]=1; 31 do{ 32 addEdge(st[top],bcnt+n,h2); 33 addEdge(bcnt+n,st[top],h2); 34 top--; 35 }while(st[top+1]!=v); 36 addEdge(u,bcnt+n,h2); 37 addEdge(bcnt+n,u,h2); 38 } 39 } 40 else if(ins[v]==1) 41 low[u]=min(low[u],dfn[v]); 42 } 43 ins[u]=2; 44 } 45 void dfs(int u,int fa){ 46 f[u]=w[u]; g[u]=0; 47 for(int i=h2[u],v;i;i=G[i].next) 48 if((v=G[i].v)!=fa){ 49 dfs(v,u); 50 f[u]=(f[u]*f[v])%Mod; 51 g[u]=(g[u]+f[v])%Mod; 52 } 53 } 54 ll ksm(ll bas,ll tm){ 55 if(tm==0) return 1; 56 ll ret=ksm(bas,tm/2); 57 ret=(ret*ret)%Mod; 58 return ((tm&1)?ret*bas:ret)%Mod; 59 } 60 ll inv(int x){return ksm(x,Mod-2);} 61 int main(){ 62 scanf("%d%d",&n,&m); 63 for(int i=1;i<=n;i++) scanf("%lld",&w[i]); 64 for(int i=1,u,v;i<=m;i++){ 65 scanf("%d%d",&u,&v); 66 addEdge(u,v,h1); addEdge(v,u,h1); 67 } 68 for(int i=1;i<=n;i++) 69 if(!dfn[i]){ 70 info[++colcnt]=1; 71 tarjan(i,0); 72 cut[i]=1; 73 sumup=(sumup+info[colcnt])%Mod; 74 head[colcnt]=i; 75 dfs(i,0); 76 } 77 for(ll i=1,k;i<=n;i++){ 78 int c=col[i]; 79 if(!cut[i]) 80 k=(sumup+Mod*2-info[c]+(info[c]*inv(w[i]))%Mod)%Mod; 81 else{ 82 if(head[c]!=i) k=(sumup+Mod*2-info[c]+(info[c]*inv((f[i])%Mod)%Mod)%Mod+g[i])%Mod; 83 else k=(sumup+Mod*2-info[c]+g[i])%Mod; 84 } 85 ans=(ans+(i*k)%Mod)%Mod; 86 } 87 printf("%lld\n",ans); 88 return 0; 89 } 奇妙代碼

?

轉載于:https://www.cnblogs.com/RogerDTZ/p/7582188.html

總結

以上是生活随笔為你收集整理的Fantasia (Tarjan+树形DP)的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。