Codeforces 633F 樹的直徑 樹形DP

2022-06-28 04:30:13 字數 2607 閱讀 9432

題意:有兩個小孩玩遊戲,每個小孩可以選擇乙個起始點,並且下乙個選擇的點必須和自己選擇的上乙個點相鄰,問兩個選的點權和的最大值是多少?

思路:首先這個問題可以轉化為求樹上兩不相交路徑的點權和的最大值,對於這種問題,我們有兩種想法:

1:樹的直徑,受之前hdu多校的那道題的啟發,我們先找出樹的直徑,然後列舉保留直徑的哪些部分,去找保留這一部分的最優解,去更新答案。

**:

#include #define inf 1e18

#define ll long long

using namespace std;

const int maxn = 100010;

vectorg[maxn];

ll tot;

int now, f[maxn];

ll d[maxn], val[maxn], sum[maxn];

bool v[maxn], v1[maxn];

ll mx[maxn];

void add(int x, int y)

void dfs(int x, int fa, ll sum)

for (auto y : g[x])

}void dfs1(int x, int fa)

d[x] += tmp;

return;

}vectora;

int main()

for (int i = 1; i < n; i++)

ll ans = 0;

tot = 0, now = 0;

dfs(1, 0, 0);

tot = 0;

dfs(now, 0, 0);

for (int i = now; i; i = f[i])

for (auto y : a)

memset(v1, 0, sizeof(v1));

for (int i = 1; i <= n; i++)

mx[a[a.size() - 1]] = d[a[a.size() - 1]];

for (int i = a.size() - 2; i >= 1; i--)

for (int i = 0; i < a.size() - 1; i++)

printf("%lld\n", ans);

}

思路2:樹形dp,我們對於每個點保留從它到葉子節點的最長路徑和次長路徑,以及以它為根的子樹中的最長路徑。dp完之後,我們對於每個節點,列舉選哪棵子樹中的節點作為一條路徑,然後去尋找另一條最長路徑。可以用字首最大值和字尾最大值去優化,以及需要注意需要考慮父節點方向對答案的影響。

**:

#include #define ll long long

#define pll pairusing namespace std;

const int maxn = 100010;

vectorg[maxn];

ll mx_path[maxn], mx_dis[maxn];

ll lmx_path[maxn], rmx_path[maxn];

pll lmx_dis[maxn], rmx_dis[maxn];

ll val[maxn];

ll ans = 0;

void add(int x, int y)

void dfs(int x, int fa)

mx_dis[x] = tmp[2] + val[x];

mx_path[x] = max(mx_path[x], tmp[1] + tmp[2] + val[x]);

return;

}int tot, a[maxn];

struct node ;

queueq;

void solve() );

while(q.size())

rmx_path[tot + 1] = rmx_path[tot + 2] = 0;

rmx_dis[tot + 1] = rmx_dis[tot + 2] = make_pair(0, 0);

for (int i = 1; i <= tot; i++) else if(mx_dis[a[i]] > lmx_dis[i].second)

} for (int i = tot; i >= 1; i--) else if(mx_dis[a[i]] > rmx_dis[i].second)

} ll tmp1 = 0;

// printf("%d\n", x);

// for (int i = 1; i <= tot; i++)

for (int i = 1; i <= tot; i++) );

tmp2 += mx_path[a[i]];

// printf("%lld\n", tmp2);

tmp1 = max(tmp1, tmp2);

}// printf("\n");

ans = max(ans, tmp1);

ans = max(ans, tmp.mx_p + mx_path[x]); }}

int main()

dfs(1, 0);

solve();

printf("%lld\n", ans);

}

codeforces 1114F 線段樹練習

這是一道用線段樹維區間值的一道題,題意很簡單,就是對於給定的乙個序列,初始時每個數的值不大於300,然後有兩中操作,乙個是對區間 l,r 的每個數乘上以個數x,乙個是詢問區間的乘積的尤拉函式值,首先對於第乙個操作顯然可以用線段樹的延遲更新來完成,對於第二個操作,我最先沒考慮資料,就想著直接維護區間的...

codeforces 1108F 最小生成樹並查集

讓我想起了徐州的第一題。還以為比那題更難 第二天早上隊友跟我聊了下這題,然後我發現這題就可以用我徐州第一題的錯誤的思路做 雖然那題因為資料特殊性a了。我們開兩個並查集,對於一段相同的邊,f1表示這段相同的邊之前的連線情況,然後從前向後列舉這段邊,如果能連就連,只更新f2,如果不能連,去f1中看看是不...

codeforces 1140 F(時間線段樹)

思路 時間線段樹部分挺裸的,乙個點能把行和列連線在一起,那麼答案就是每個聯通快裡面行的個數乘上列的個數,把行和列看成點的思想好像挺常見的,網路流建圖什麼的也可以經常可以看見這種思想,紀錄一下 pragma gcc optimize 3 include include include include ...