沒有上司的舞會帶修版(ddp)

2022-05-11 15:45:11 字數 3442 閱讀 8143

簡化版看了簡化版之後容易想到乙個dp。

$dp_$代表$u$的子樹內不選$u$的最大答案。

$dp_$代表$u$的子樹內選$u$的最大答案。

有轉移方程:

$dp_=\sum_ max(dp_, dp_)$。

$dp_=(\sum_ dp_)+a_u$。

然後對於ddp的模板題我們就得到了乙個$o(nm)$的優秀演算法。

接下來我們就來看看怎麼用ddp的套路來切掉這道題。

因為ddp只是利用樹剖把樹剖成一條條鏈,然後再鏈上做ddp,所以我們要有乙個適應鏈dp的方程和狀態。

我們在樹剖時只能處理重邊的結果,不能處理輕邊的結果,所以我們要先把輕邊的結果算出來。

設$u$的重兒子為$son(u)$。

因為是在重鏈上序列dp,所以我們要先把重兒子分離出來。

令$g_=\sum_ max(dp_,dp_)$,$g_=(\sum_ dp_) + a_u$。

則有$dp_=g_+max(dp_, dp_)$,$dp_=g_+dp_$。

我們發現能做ddp還有乙個前提是變成序列dp後可以用廣義矩乘來表示轉移,比如上面的例子可以表示成:

$\left[ \begin g_ & g_ \\ g_ & -inf \end \right] \times \left[ \begin dp_ \\ dp_ \end \right]=\left[ \begin dp_ \\ dp_ \end \right] $

然後我們就可以愉快的ddp了!要想查任意點的dp值只需查從它這個點到它所在的重鏈的結尾上的點的矩陣乘積即可(所以我們還需維護鏈尾),因為鏈尾的矩陣即為其dp值矩陣。

而這個$g$陣列和$dp$陣列都是可以在樹鏈剖分時預處理出來的。

修改我們發現我們只需修改$g$的值,即矩陣即可。

對於乙個位置先把它的修改了,然後跳到它的鏈頭的父親,繼續迴圈做直到到根。

為什麼可以這麼做因為$g$是與重鏈無關的,只用修改輕鏈的情況。

具體修改時需要記錄前乙個點(即前一條重鏈的聯投)的dp值修改前後的增量,然後用之前的值加上其即可(因為是修改乙個輕兒子)。

具體可看**。

查詢查詢時查根的dp值即可。

#include #include 

#include

using

namespace

std;

const

int n = 100010;//

輸入輸出

template void read(t &x)

template

void

write(t x)

template

void

print(t x)

template

void cmax(t &x, t y)

template

void cmin(t &x, t y)

int n;//

節點個數

int m;//

操作個數

int a[n];//

初始值

int dp[n][2];//

dp陣列

//前向星

namespace

qxxedge[n

<< 1

];

inthead[n], tot;

inline

void add(int u, int v)

}using

namespace

qxx;

//矩陣

namespace

matrixa[n];

inline

void init(matrix &x)

inline matrix mul(matrix x, matrix y)

}using

namespace

matrix;

//樹鏈剖分

namespace

tcp }

void dfs2(int x, int chain)

dp[x][

0] += a[x].arr[1][1

]; dp[x][

1] += a[x].arr[2][1

]; }

}using

namespace

tcp;

namespace

segment_treetr[n

<< 2

]; inline

void push_up(int p)

void build(int p, int l, int

r)

int mid = (l + r) >> 1

; build(p

<< 1

, l, mid);

build(p

<< 1 | 1, mid + 1

, r);

push_up(p);

}void change(int p, int l, int r, int

pos)

int mid = (l + r) >> 1

;

if (pos <= mid) change(p << 1

, l, mid, pos);

else change(p << 1 | 1, mid + 1

, r, pos);

push_up(p);

}matrix query(

int p, int l, int r, int l, int

r)

int mid = (l + r) >> 1

;

if (r <= mid) return query(p << 1

, l, mid, l, r);

else

if (l > mid) return query(p << 1 | 1, mid + 1

, r, l, r);

else

return mul(query(p << 1, l, mid, l, mid), query(p << 1 | 1, mid + 1, r, mid + 1

, r));

}}using

namespace

segment_tree;

intmain()

dfs1(1);

dfs2(

1, 1

); build(

1, 1

, n);

while (m--)

matrix ans = query(1, 1, n, top[1], end[top[1

]]);

print(max(ans.arr[

1][1], ans.arr[2][1

]));

}return0;

}

沒有上司的舞會

題目描述 description ural大學有n個職員,編號為1 n。他們有從屬關係,也就是說他們的關係就像一棵以校長為根的樹,父結點就是子結點的直接上司。每個職員有乙個快樂指數。現在有個周年慶宴會,要求與會職員的快樂指數最大。但是,沒有職員願和直接上司一起與會。輸入描述 input descri...

沒有上司的舞會

ural大學有 n 個職員,編號為 1 n 他們有從屬關係,也就是說他們的關係就像一棵以校長為根的樹,父結點就是子結點的直接上司。每個職員有乙個快樂指數。現在有個周年慶宴會,要求與會職員的快樂指數最大。但是,沒有職員願和直接上司一起與會。第一行乙個整數n。1 n 6000 接下來n行,第i 1行表示...

沒有上司的舞會

某大學有n個職員,編號為1 n。他們之間有從屬關係,也就是說他們的關係就像一棵以校長為根的樹,父結點就是子結點的直接上司。現在有個周年慶宴會,宴會每邀請來乙個職員都會增加一定的快樂指數ri,但是呢,如果某個職員的上司來參加舞會了,那麼這個職員就無論如何也不肯來參加舞會了。所以,請你程式設計計算,邀請...