生活随笔
收集整理的這篇文章主要介紹了
newcode Gene Tree 点分治
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
傳送門
文章目錄
題意:
求一棵樹的每對葉子節點之間距離平方的和。
思路:
這個題貌似可以容斥,但是我不會,所以我寫了個淀粉質。
要知道,淀粉質的思想就是將子樹內部的遞歸處理,當前這層處理不同子樹之間的距離即可,考慮化簡式子分別求貢獻。
假設(ai+aj)2(a_i+a_j)^2(ai?+aj?)2為兩點間距離平方和,ai,aja_i,a_jai?,aj?為葉子到當前找的偽重心的距離,把式子化簡出來就是ai2+aj2+2?ai?aja_i^2+a_j^2+2*a_i*a_jai2?+aj2?+2?ai??aj?,考慮每一塊的貢獻。
我們設當前遍歷的子樹的葉子距離為aia_iai?,之前遍歷過的子樹的葉子距離為aja_jaj?,個數為cntcntcnt個,平方和為sum1sum1sum1,和為sum2sum2sum2。算這個子樹和之前遍歷過的子樹信息的時候,ai2a_i^2ai2?的貢獻是cnt?ai2cnt*a_i^2cnt?ai2?,bi2b_i^2bi2?就是sum1sum1sum1,2?ai?aj2*a_i*a_j2?ai??aj?的貢獻為2?ai?sum22*a_i*sum22?ai??sum2,這樣我們就可以分開統計貢獻,淀粉質板子套一下就好啦。
#include<cstdio>
#include<iostream>
#include<string>
#include<cstring>
#include<map>
#include<cmath>
#include<cctype>
#include<vector>
#include<set>
#include<queue>
#include<algorithm>
#include<sstream>
#include<ctime>
#include<cstdlib>
#define X first
#define Y second
#define L (u<<1)
#define R (u<<1|1)
#define pb push_back
#define mk make_pair
#define Mid (tr[u].l+tr[u].r>>1)
#define Len(u) (tr[u].r-tr[u].l+1)
#define random(a,b) ((a)+rand()%((b)-(a)+1))
#define db puts("---")
using namespace std
;
typedef long long LL
;
typedef unsigned long long ULL
;
typedef pair
<int,int> PII
;const int N
=100010,M
=N
*2,mod
=1e9+7,INF
=0x3f3f3f3f;
const double eps
=1e-6;int n
,m
;
int h
[N
],e
[M
],ne
[M
],w
[M
],idx
;
LL p
[N
],q
[N
];
int d
[N
];
bool st
[N
];void add(int a
,int b
,int c
)
{e
[idx
]=b
,w
[idx
]=c
,ne
[idx
]=h
[a
],h
[a
]=idx
++;
}int get_wc(int u
,int f
,int tot
,int &wc
,int &mi
)
{if(st
[u
]) return 0;int sum
=1,mx
=0;for(int i
=h
[u
];~i
;i
=ne
[i
]){int j
=e
[i
];if(j
==f
) continue;int t
=get_wc(j
,u
,tot
,wc
,mi
);mx
=max(mx
,t
); sum
+=t
;}mx
=max(mx
,tot
-sum
);if(mx
<mi
) wc
=u
,mi
=mx
;return sum
;
}int get_size(int u
,int f
)
{if(st
[u
]) return 0;int sum
=1;for(int i
=h
[u
];~i
;i
=ne
[i
])if(e
[i
]!=f
)sum
+=get_size(e
[i
],u
);return sum
;
}void get_dis(int u
,int f
,int dis
,int &qt
)
{if(st
[u
]) return ;int cnt
=0;for(int i
=h
[u
];~i
;i
=ne
[i
]){int j
=e
[i
];if(j
==f
) continue;cnt
++;get_dis(j
,u
,dis
+w
[i
],qt
);}if(d
[u
]==1) q
[qt
++]=dis
;
}LL
cal(int u
)
{if(st
[u
]) return 0;LL ans
=0; int tt
=INF
;get_wc(u
,-1,get_size(u
,-1),u
,tt
);st
[u
]=true;LL pt
=0,pre
=0,cnt
=0;for(int i
=h
[u
];~i
;i
=ne
[i
]){int j
=e
[i
],qt
=0;get_dis(j
,-1,w
[i
],qt
);for(int k
=0;k
<qt
;k
++) ans
+=1ll*q
[k
]*q
[k
]*cnt
,ans
+=1ll*2*pt
*q
[k
],ans
+=pre
;for(int k
=0;k
<qt
;k
++) pt
+=q
[k
],pre
+=1ll*q
[k
]*q
[k
],cnt
++;}for(int i
=h
[u
];~i
;i
=ne
[i
]) ans
+=cal(e
[i
]);return ans
;
}int main()
{
scanf("%d",&n
); memset(h
,-1,sizeof(h
));memset(st
,false,sizeof(st
));for(int i
=1;i
<=n
-1;i
++){int a
,b
,c
; scanf("%d%d%d",&a
,&b
,&c
);add(a
,b
,c
); add(b
,a
,c
);d
[a
]++; d
[b
]++;}printf("%lld\n",cal(1));return 0;
}
總結
以上是生活随笔為你收集整理的newcode Gene Tree 点分治的全部內容,希望文章能夠幫你解決所遇到的問題。
如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。