先將所給的圖(無根樹)轉化為有根樹,可以用一遍dfs完成。
轉化為有根樹後,對於i點,能夠產生與它聯合權值的點,要麼是它第乙個祖先(或孫子),要麼是與它深度相同的兄弟。i與它的祖先(孫子)產生的聯合權值容易計算,可以在o(1)內完成,但是與它的兄弟的權值,用樸素的演算法就需要o(n)了,例如i1,i2,i3的父節點都為k,那麼i1,i2,i3之間總的聯合權值就為:2 * ( w[i1] * w[i2] + w[i1] * w[i3] + w[i2] * w[i3] )。然而用樸素演算法做的會tle,所以得考慮優化。
我們分開來觀察一下,對於i1其聯合權值為,w[i1] * ( w[i2] + w[i3] ),i2為 w[i2] * w[i3], i3為0。現在記sum=w[i1] + w[i2] + w[i3],那麼上式會化為,w[i1] * ( sum- w[i1] ),w[i2] * ( sum- w[i1] - w[i2] ),w[i3] * ( sum - w[i1] - w[i2] - w[i3] ),因此,我們可以對於每個節點,記錄它的子節點所有權值之和,另外,對於某個父節點k,我們通過有序遍歷它的子節點,這樣就可以設定temp,記錄遍歷過程中經過的子節點權值和,如此一來,對於k的某一子節點i,其聯合權值就可以簡化為w[i] * (sum - temp)。
ps:以上各個過程均通過dfs完成。
**如下:
#include#include#include#include#include#include#include#include#pragma comment(linker,"/stack:102400000,102400000")
using namespace std;
typedef long long ll;
const int maxn=2e5+5;
const int mod=10007;
ll w[maxn],ans,sum;
int head[maxn],cnt,fa[maxn];
bool vis[maxn];
struct node
}node[maxn];
struct edge
e[maxn<<1];
void addedge(int u,int v)
void dfs(int u,int pre,int d)
inline void out(int x)
int main()
for(int i=1;i<=n;++i)
scanf("%lld",&w[i]);
fa[0]=w[0]=0;
dfs(1,0,1);
sum=0; ans=0;
for(int i=1;i<=n;++i) vis[i]=0;
dfs(1);
printf("%lld %lld\n",ans,(2*sum)%mod);
return 0;
}
洛谷P1351 聯合權值
無向連通圖g 有n 個點,n 1 條邊。點從1 到n 依次編號,編號為 i 的點的權值為w i 每條邊的長度均為1 圖上兩點 u v 的距離定義為u 點到v 點的最短距離。對於圖g 上的點對 u,v 若它們的距離為2 則它們之間會產生wu wv 的聯合權值。請問圖g 上所有可產生聯合權值的有序點對中...
P1351 聯合權值
無向連通圖g有n個點,n 1 條邊。點從1到n依次編號,編號為i的點的權值為w i 每條邊的長度均為 1。圖上兩點 u,v 的距離定義為 u 點到 v 點的最短距離。對於圖 g 上的點對 u,v 若它們的距離為 2,則它們之間會產生wv wu的聯合權值。請問圖 g上所有可產生聯合權值的有序點對中,聯...
P1351 聯合權值
然而這只是一道普及 提高的大水題 洛谷鏈結 這道題是2014年提高組day1的第二題。簡單題意就是在樹上每個點都有權值,相鄰兩點的距離為1,求距離為2的點的權值乘積的和以及最大值。基本思路就是遍歷整棵樹,然後找到距離該點距離為2的點,計算距離,更新最大值和乘積和。但這樣就很慢了。所以我們可以遍歷中間...