日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

【树链剖分】【线段树】树的统计(金牌导航 树链剖分-1)

發(fā)布時(shí)間:2023/12/3 编程问答 34 豆豆
生活随笔 收集整理的這篇文章主要介紹了 【树链剖分】【线段树】树的统计(金牌导航 树链剖分-1) 小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

樹的統(tǒng)計(jì)

金牌導(dǎo)航 樹鏈剖分-1

題目大意

給出一棵樹,讓你做若干操作,操作如下:
1.修改一個(gè)節(jié)點(diǎn)的值
2.查詢兩個(gè)節(jié)點(diǎn)之間路徑的最大值
3.查詢兩個(gè)節(jié)點(diǎn)之間路徑的和

輸入樣例

4 1 2 2 3 4 1 4 2 1 3 12 QMAX 3 4 QMAX 3 3 QMAX 3 2 QMAX 2 3 QSUM 3 4 QSUM 2 1 CHANGE 1 5 QMAX 3 4 CHANGE 3 6 QMAX 3 4 QMAX 2 4 QSUM 3 4

輸出樣例

4 1 2 2 10 6 5 6 5 16

數(shù)據(jù)范圍

1?N?3×104,0?q?2×105,?3×104?si?3×1041\leqslant N\leqslant 3\times 10^4,0\leqslant q\leqslant 2\times10^5,-3\times 10^4\leqslant s_i\leqslant 3\times 10^41?N?3×104,0?q?2×105,?3×104?si??3×104

解題思路

樹鏈剖分,然后用線段樹維護(hù)重鏈,每個(gè)節(jié)點(diǎn)維護(hù)最大值和權(quán)值和

代碼

#include<cstdio> #include<cstring> #include<iostream> #include<algorithm> #define ll long long #define N 30030 using namespace std; int n, m, x, y, w, tot, ansmax, anssum; int a[N], s[N<<4], v[N], fa[N], hs[N], han[N], dfn[N], dep[N], size[N], head[N], maxx[N<<4]; string str; struct rec {int to, next; }e[N<<1]; void add(int x, int y) {e[++tot].to = y;e[tot].next = head[x];head[x] = tot; } void dfs1(int x)//找重兒子 {size[x] = 1;for (int i = head[x]; i; i = e[i].next)if (e[i].to != fa[x]){fa[e[i].to] = x;dep[e[i].to] = dep[x] + 1;dfs1(e[i].to);size[x] += size[e[i].to];if (size[e[i].to] > size[hs[x]]) hs[x] = e[i].to;}return; } void dfs2(int x) {dfn[x] = ++w;v[w] = x;if (hs[x]){han[hs[x]] = han[x];//重祖先dfs2(hs[x]);}for (int i = head[x]; i; i = e[i].next)if (e[i].to != fa[x] && e[i].to != hs[x]){han[e[i].to] = e[i].to;dfs2(e[i].to);} } void up(int x) {s[x] = s[x * 2] + s[x * 2 + 1];maxx[x] = max(maxx[x * 2], maxx[x * 2 + 1]);return; } void build(int now, int l, int r)//線段樹維護(hù) {if (l == r){maxx[now] = s[now] = a[v[l]];return;}int mid = (l + r) >> 1;build(now * 2, l, mid);build(now * 2 + 1, mid + 1, r);up(now);return; } void change(int x, int y, int now, int l, int r) {if (l == r){maxx[now] = s[now] = y;return;}int mid = (l + r) >> 1;if (x <= mid) change(x, y, now * 2, l, mid);else change(x, y, now * 2 + 1, mid + 1, r);up(now);return; } void ask(int now, int ql, int qr, int l, int r) {if (l == ql && r == qr){ansmax = max(ansmax, maxx[now]);anssum += s[now];return;}int mid = (l + r) >> 1;if (qr <= mid) {ask(now * 2, ql, qr, l, mid); return;}if (ql > mid) {ask(now * 2 + 1, ql, qr, mid + 1, r); return;}ask(now * 2, ql, mid, l, mid);ask(now * 2 + 1, mid + 1, qr, mid + 1, r);return; } void askk(int x, int y)//計(jì)算路徑長度 {anssum = 0;ansmax = -N;while(han[x] != han[y]){if (dep[han[x]] < dep[han[y]]) swap(x, y);ask(1, dfn[han[x]], dfn[x], 1, n);x = fa[han[x]];}if (dep[x] < dep[y]) swap(x, y);ask(1, dfn[y], dfn[x], 1, n);return; } int main() {scanf("%d", &n);for (int i = 1; i < n; ++i){scanf("%d%d", &x, &y);add(x, y);add(y, x);}for (int i = 1; i <= n; ++i)scanf("%d", &a[i]);fa[1] = 1;han[1] = 1;dfs1(1);dfs2(1);build(1, 1, n);scanf("%d", &m);while(m--){cin>>str;scanf("%d%d", &x, &y);if (str == "CHANGE"){change(dfn[x], y, 1, 1, n);}else{askk(x, y);if (str == "QSUM") printf("%d\n", anssum);else if (str == "QMAX") printf("%d\n", ansmax);}}return 0; }

總結(jié)

以上是生活随笔為你收集整理的【树链剖分】【线段树】树的统计(金牌导航 树链剖分-1)的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。