給你一棵帶點權的樹,求將樹變成一堆不相交的鏈,而且這些鏈的權值和非負的方案數。
顯然這道題是個dpdp
dp。首先求個字首和sum
sumsu
m。為了後面講述方便,我這樣設:fi,
jf_
fi,j
表示以i
ii為根的子樹,其中某條鏈從x
xx伸出到i
ii的方案數,而且sum
x=
jsum_x=j
sumx=
j。還有設g
ig_i
gi表示以i
ii為根的,沒有伸出去的鏈的方案數。
顯然有這樣的轉移:
∏ gi
→fx,
sumx
fy,j
∏i≠y
gi→f
x,
j\prod g_i\to f_\\ f_\prod_ g_i\to f_x,j
∏gi→f
x,su
mx
fy,j
i̸
=y∏
gi→
fx,jfx
,j→g
x(j−
sumf
ax≥0
)fy,
jfz,
k∏i≠
y,i≠
zgi→
gx(j
+k−2
sumx
+ax≥
0)
f_ \to g_x \ (j-sum_\geq 0)\\ f_f_\prod_g_i\to g_x \ (j+k-2sum_x+a_x\geq 0)
fx,j→
gx(
j−su
mfax
≥0
)fy,
jfz
,ki
̸=y
,i̸
=z∏
gi→
gx(
j+k−
2sum
x+a
x≥0
)如果直接這樣搞肯定會**。所以考慮用線段樹來維護fff。
由於可能會出現g
gg值為0
00的情況,所以不能直接用逆元來搞。
要維護個字首積和字尾積。
首先要求出重兒子,把重兒子作為第乙個兒子,然後線段樹合併之前也啟發式合併。
具體來說,我們欽定j
j< k。在合併的時候(設前面子樹合併出來的線段樹為a aa,這個線段樹為b bb)當前的兒子作為k kk,遍歷b bb的所有葉子節點,並在a aa中區間詢問。這時候記得要乘上字尾積。將詢問出來的東西加在g xg_x gx中。 然後兩個合併在一起。記得在合併之前,整個a aa乘子樹的g xg_x gx,整個b bb乘字首積 。搞完這個再合併。 最後你就會愉快地發現,所有子樹合併之後就是上面第二行式子。這樣只需要把第一行的加進去。第四行的式子已經計算完了,只需要再加上第乙個式子就可以了。 然而這不是題解的做法,作為乙個小蒟蒻,表示看不懂題解……using
namespace std;
#include
#include
#include
#include
#define n 100010
#define inf 1000000000
#define mo 1000000007
int n;
int a[n]
;struct edge e[n*2]
;int ne;
edge *last[n]
;struct node *null;
struct node
inline
void
pushdown()
}inline
void
update()
} d[n*40]
;int cnt;
node *rt[n]
;inline node *
newnode()
);}void
add(node *
&t,int l,
int r,
int x,
int c)
t->
pushdown()
;int mid=l+r>>1;
if(x<=mid)
add(t-
>l,l,mid,x,c)
;else
add(t-
>r,mid+
1,r,x,c)
; t-
>
update()
;}intquery
(node *t,
int l,
int r,
int st,
int en)
node *
merge
(node *a,node *b)
intcalc
(node *t,
int l,
int r,node *rt,
int bor)
int fa[n]
,sum[n]
,siz[n]
,hs[n]
;int son[n]
,ns,pre[n]
,suc[n]
;int g[n]
;voiddp(
int x)if(
!hs[x]
) son[ns=1]
=hs[x]
; pre[0]
=1,pre[1]
=g[hs[x]];
for(edge *ei=last[x]
;ei;ei=ei-
>las)
if(ei-
>to!=fa[x]
&& ei-
>to!=hs[x]
) suc[ns+1]
=1;for
(int i=ns;i>=1;
--i)
suc[i]=(
long
long
)suc[i+1]
*g[son[i]
]%mo;
rt[x]
=rt[hs[x]];
for(
int i=
2;i<=ns;
++i)
add(rt[x]
,-inf,inf,sum[x]
,pre[ns]);
g[x]+=
query
(rt[x]
,-inf,inf,sum[fa[x]
],inf)
; g[x]
>=mo?g[x]
-=mo:0;
}int
main()
; last[u]
=e+ne++
; e[ne]=;
last[v]
=e+ne++;}
null=d;
*null=;dp
(n>>1)
;printf
("%d\n"
,g[n>>1]
);return0;
}
好多樹形dp都可以用線段樹合併來優化啊……
JZOJ4331 清華集訓模擬 樹
給你一棵帶點權的樹,求將樹變成一堆不相交的鏈,而且這些鏈的權值和非負的方案數。顯然這道題是個 dp 首先求個字首和 sum 為了後面講述方便,我這樣設 f 表示以 i 為根的子樹,其中某條鏈從 x 伸出到 i 的方案數,而且 sum x j 還有設 g i 表示以 i 為根的,沒有伸出去的鏈的方案數...
JZOJ 4330 清華集訓模擬 幾何題
這題的複雜度是o 106log 106 的fft 害怕.jpg 預處理cnt i j k 表示x,y,z的差為i,j,k的有多少對,首先,xi xj可以變成xi mx xj mx為最大xi 那麼每位都是非負數了,現在要做3維的多項式乘法,考慮用2mx進製儲存這三個數,壓在一起變乙個數,這樣就把3維變...
JZOJ4330 清華集訓模擬 幾何題
也懶得解釋題目大意了 正解居然是fft fftff t?不要看題目的那個式子這麼長,也不要在那個式子上下手。其實我們會發現,不同的 xi xj,yi y j,zi zj x i x j,y i y j,z i z j xi x j y i y j z i z j 並不多。如果我們求出每個三元組的出現...