樹鏈剖分+線段樹 CF 593D Happy Tree Party(快樂樹聚會)

 

題目連接c++

題意:數組

  有n個點的一棵樹,兩種操做:ide

  1. a到b的路徑上,給一個y,對於路徑上每一條邊,進行操做,問最後的y;函數

  2. 修改某個條邊p的值爲cthis

思路:spa

  鏈上操做的問題,想樹鏈剖分和LCT,對於第一種操做,由於是向下取整,考慮y除以路徑上全部邊乘積,即;對於第二種操做,就是線段樹上的單點更新。由於給的是邊的序號,首先每一個id能知道對應的邊值(ide[])和鏈接的點(idv[])。還有乘法溢出的處理,寫成函數方便多了。debug

另外:code

  1. 用dfn來替換dep徹底沒有問題,那之後就用dfn吧。2. 第二次DFS,要先去重兒子的路,這樣dfn[son[u]]=dfn[u]+1,son數組也省了。3. 代碼debug水平有待提高。4. 樹的建圖用vector就好了,不須要鄰接表(n-1條邊)。orm

#include <bits/stdc++.h>

typedef long long ll;
const int N = 2e5 + 5;
const ll INF = 2e18;

std::vector<std::pair<int, int> > edges[N];
int n, m;

int dfn[N], fa[N], son[N], sz[N], belong[N];
ll ide[N];
int idv[N];
int tim;

inline ll mul(ll a, ll b) {
    if (a != 0 && b > INF / a) return INF;
    return a * b;
}

void DFS2(int u, int chain) {
    dfn[u] = ++tim;
    belong[u] = chain;
    if (son[u] != 0) {
        DFS2 (son[u], chain);
    }
    for (auto e: edges[u]) {
        int v = e.first;
        if (v == fa[u] || v == son[u]) continue;
        DFS2 (v, v);
    }
}

void DFS1(int u, int pa) {
    sz[u] = 1;
    fa[u] = pa;
    for (auto e: edges[u]) {
        int v = e.first, id = e.second;
        if (v == pa) continue;
        idv[id] = v;
        DFS1 (v, u);
        if (sz[v] > sz[son[u]]) son[u] = v;
        sz[u] += sz[v];
    }
}

#define lson l, mid, o << 1
#define rson mid + 1, r, o << 1 | 1

ll val[N<<2];

void push_up(int o) {
    val[o] = mul (val[o<<1], val[o<<1|1]);
}

void tree_updata(int p, ll c, int l, int r, int o) {
    if (l == r) {
        val[o] = c;
        return ;
    }
    int mid = l + r >> 1;
    if (p <= mid) tree_updata (p, c, lson);
    else tree_updata (p, c, rson);
    push_up (o);
}

ll tree_query(int ql, int qr, int l, int r, int o) {
    if (ql <= l && r <= qr) {
        return val[o];
    }
    int mid = l + r >> 1;
    ll ret = 1;
    if (ql <= mid) ret = mul (ret, tree_query (ql, qr, lson));
    if (qr > mid) ret = mul (ret, tree_query (ql, qr, rson));
    return ret;
}

ll query(int a, int b) {
    ll ret = 1;
    int p = belong[a], q = belong[b];
    while (p != q) {
        if (dfn[p] < dfn[q]) {
            std::swap (p, q);
            std::swap (a, b);
        }
        ret = mul (ret, tree_query (dfn[p], dfn[a], 1, n, 1));
        a = fa[p];
        p = belong[a];
    }
    if (dfn[a] < dfn[b]) std::swap (a, b);
    if (a != b) {
        ret = mul (ret, tree_query (dfn[son[b]], dfn[a], 1, n, 1));
    }
    return ret;
}

void modify(int id, ll c) {
    tree_updata (dfn[idv[id]], c, 1, n, 1);
}

void prepare() {
    DFS1 (1, 0);
    tim = 0;
    DFS2 (1, 1);
    for (int i=1; i<n; ++i) {
        tree_updata (dfn[idv[i]], ide[i], 1, n, 1);
    }
}

int main() {
    scanf ("%d%d", &n, &m);
    for (int i=1; i<n; ++i) {
        int u, v;
        ll w;
        scanf ("%d%d%I64d", &u, &v, &w);
        ide[i] = w;
        edges[u].push_back ({v, i});
        edges[v].push_back ({u, i});
    }
    
    prepare ();

    for (int i=0; i<m; ++i) {
        int t, a, b;
        ll c;
        scanf ("%d%d", &t, &a);
        if (t == 1) {
            scanf ("%d%I64d", &b, &c);
            printf ("%I64d\n", c / query (a, b));
        } else {
            scanf ("%I64d", &c);
            modify (a, c);
        }
    }
    return 0;
}
相關文章
相關標籤/搜索