1. 程式人生 > >5692 Snacks (線段樹+ dfs)

5692 Snacks (線段樹+ dfs)

題意:

一棵樹0為頂點,n個頂點 (n-1)條邊,問如果必須經過一個點,權值最大的一條路的權值是多少

思路:

因為n個點,(n-1)條邊,所以從頂點每個點只有一條路,可以用dfs求出從頂點到每一個點的距離,而且題目中有修改點的值的要求,所以可以想到線段樹,而用dfs的話,會發現一個父節點的所有子節點遍歷完後才會遍歷到這個父節點。 所以如果在dfs途中,對每個點重新編號的話,父節點所有的子節點可以組成一個連續的區間,[L,R],L是指所有子節點的最小值,R是父節點本身(因為父節點一定比它的所有子節點大),而求經過這個父節點的最大權值,就是它的區間的最大值,而區間的最值可用線段樹解決 那樣例舉個例子: 在這裡插入圖片描述

經過dfs後並排序後,藍色是排序後的編號,num[i]是0->i(i是排序後編號)的距離,粉紅的是每個父節點的子節點的區間範圍 在這裡插入圖片描述 而排成線段樹是就是這樣 在這裡插入圖片描述 對於每個父節點都有一個區間代表子節點的範圍,這是可用線段樹求出,修改同樣用線段樹修改

AC程式碼

#include <iostream>
#include <string.h>
#include <string>
#include <math.h>
#include <stdlib.h>
#include <vector>
#include <set>
#include <map> #include <queue> #include <stack> #include <bitset> #include <algorithm> #include <stdio.h> #include <deque> #pragma comment(linker, "/STACK:1024000000,1024000000") using namespace std; #define LL long long #define ull unsigned long long #define INF 0x3f3f3f3f
#define maxn 200005 #define eps 0.00000001 #define PI acos(-1.0) #define M 1000000007 struct Edge{ int v, nxt; }edge[maxn << 2]; struct Tree{ int l, r; LL w, lazy; }tree[maxn << 2]; int head[maxn], tot, L[maxn], R[maxn], Index, Ll, Rr; LL num[maxn], w[maxn], ans, ww; void init() { Index = tot = 0; memset(head, -1, sizeof(head)); } void addEdge(int u, int v) { edge[tot].v = v; edge[tot].nxt = head[u]; head[u] = tot ++; edge[tot].v = u; edge[tot].nxt = head[v]; head[v] = tot ++; } void Built(int k, int ll, int rr) { tree[k].l = ll; tree[k].r = rr; tree[k].lazy = 0; if(ll == rr) { tree[k].w = num[ll]; return ; } int mm = (ll + rr) >> 1; Built(k << 1, ll, mm); Built(k << 1|1, mm + 1, rr); tree[k].w = max(tree[k << 1].w, tree[k << 1|1].w); } void Down(int k) { tree[k << 1].lazy += tree[k].lazy; tree[k << 1|1].lazy += tree[k].lazy; tree[k << 1].w += tree[k].lazy; tree[k << 1|1].w += tree[k].lazy; tree[k].lazy = 0; } void change_Interval(int k) { if(tree[k].l >= Ll && tree[k].r <= Rr) { tree[k].w += ww; tree[k].lazy += ww; return; } if(tree[k].lazy != 0) Down(k); int mm = (tree[k].l + tree[k].r) >> 1; if(mm >= Ll) change_Interval(k << 1); if(mm < Rr) change_Interval(k << 1|1); tree[k].w = max(tree[k << 1].w, tree[k << 1|1].w); } void ask_Interval(int k) { if(tree[k].l >= Ll && tree[k].r <= Rr) { ans = max(ans, tree[k].w); return; } if(tree[k].lazy != 0) Down(k); int mm = (tree[k].l + tree[k].r) >> 1; if(mm >= Ll) ask_Interval(k << 1); if(mm < Rr) ask_Interval(k << 1|1); } void dfs(int u, int parent, LL sum) { sum += w[u]; L[u] = INF; for (int i = head[u]; i + 1; i = edge[i].nxt) { int son = edge[i].v; if(son == parent) continue; dfs(son, u, sum); L[u] = min(L[u], L[son]); } R[u] = ++Index; num[Index] = sum; if(L[u] == INF) L[u] = R[u]; } int main(int argc, const char * argv[]) { int T; scanf("%d", &T); for (int Case = 1; Case <= T; Case ++) { printf("Case #%d:\n", Case); init(); int n, m; scanf("%d %d", &n, &m); for (int i = 1; i < n; i ++) { int u, v; scanf("%d %d", &u, &v); addEdge(u, v); } for (int i = 0; i < n; i ++) scanf("%lld", &w[i]); dfs(0, 0, 0); Built(1, 1, n); for (int i = 0; i < m; i ++) { int flag; scanf("%d", &flag); if(!flag) { int wh, y; scanf("%d %d", &wh, &y); ww = y - w[wh]; Ll = L[wh]; Rr = R[wh]; w[wh] = y; change_Interval(1); }else { int wh; scanf("%d", &wh); ans = -9999999999999999; Ll = L[wh]; Rr = R[wh]; ask_Interval(1); printf("%lld\n", ans); } } } return 0; }