天天看點

HDU-3966 (樹鍊剖分+線段樹)

#include <cstdio>
#include <cstring>
#include <algorithm>
#define lson l, m, rt<<1
#define rson m+1, r, rt<<1|1
using namespace std;
const int maxn = 50010;
struct Edge{
    int v, nxt;
}e[maxn << 2];
int first[maxn];
int cnt = 0;
int idx = 0;
int dep[maxn], son[maxn], size[maxn], top[maxn], w[maxn],a[maxn], fa[maxn];
int tree[maxn<<2];
int lazy[maxn<<2];
void addedge(int u, int v){
    e[++cnt].v = v;
    e[cnt].nxt = first[u];
    first[u] = cnt;
    e[++cnt].v = u;
    e[cnt].nxt = first[v];
    first[v] = cnt;
}
void dfs(int u){
    size[u] = 1;
    son[u] = 0;
    for(int i = first[u]; i; i = e[i].nxt){
        int v = e[i].v;
        if(dep[v] == 0){
            dep[v] = dep[u] + 1;
            fa[v] = u;
            dfs(v);
            size[u] += size[v];
            if(size[v] > size[son[u]])
                son[u] = v;
        }
    }
}

void dfstop(int u, int tp)
{
    w[u] = ++idx; top[u] = tp;
    if(son[u] != 0)
        dfstop(son[u], tp);
    for(int i = first[u]; i; i = e[i].nxt){
        int v = e[i].v;
        if(dep[u] + 1 == dep[v] && v != son[u]){
            dfstop(v, v);
        }
    }
}

void init()
{
    memset(first, 0, sizeof(first));
    memset(lazy, 0, sizeof(lazy));
    memset(dep, 0, sizeof(dep));
    memset(tree, 0, sizeof(tree));
    dep[1] = 1;
    idx = 0;
    cnt = 0;
}
void pushdown(int rt){
    lazy[rt<<1] += lazy[rt];
    lazy[rt << 1|1] += lazy[rt];
    lazy[rt] = 0;
}
void update(int l, int r, int rt, int L, int R, int x)
{
    if(l == r){
        tree[rt] = tree[rt] + lazy[rt] + x;
        lazy[rt] = 0;
        return;
    }
    if(L <= l && r <= R){
        lazy[rt] += x;
        return ;
    }
    int m = (l + r) >> 1;
    pushdown(rt);
    if(L <= m)
        update(lson, L, R, x);
    if(m < R)
        update(rson, L, R, x);
}
void query(int l, int r, int rt, int L)
{
    if(l == r){
        tree[rt] += lazy[rt];
        lazy[rt] = 0;
        printf("%d\n", tree[rt]);
        return ;
    }
    pushdown(rt);
    int m = (l + r) >> 1;
    if(L <= m)
        query(lson, L);
    else 
        query(rson, L);
}
int main()
{
    int n, m, p;
    while(~scanf("%d%d%d", &n, &m, &p)){
        init();
        for(int i = 1; i <= n; i++){
            scanf("%d", &a[i]);
        }
        for(int i = 0; i < m; i++){
            int u, v;
            scanf("%d%d", &u, &v);
            addedge(u, v);
        }
        dfs(1);
        dfstop(1, 1);
        for(int i = 1; i <= n; i++){
            update(1, idx, 1, w[i], w[i], a[i]);
        }
        for(int i = 0; i < p; i++){
            char str[2];
            int u, v, k;
            scanf("%s", str);
            if(str[0] == 'I' || str[0] == 'D'){
                scanf("%d%d%d", &u, &v, &k);
                if(str[0] == 'D') k = -k;
                while(top[u] != top[v]){
                    if(dep[top[u]] < dep[top[v]]) swap(u, v);
                    update(1, idx, 1, w[top[u]], w[u], k);
                    u = fa[top[u]];
                }
                if(w[u] <= w[v])
                    update(1, idx, 1, w[u], w[v], k);
                else update(1, idx, 1, w[v], w[u], k);
            }
            else{
                scanf("%d", &u);
                query(1, idx, 1, w[u]);
            }
        }
    }
    return 0;
}
           

樹鍊指樹上的路徑。分重鍊和輕鍊兩種。具體思想請移步: (樹鍊剖分)點選打開連結

其實也很容易了解,就是把樹上的路徑拆開然後放入到線段樹裡維護。son[u] 在的結點和u的結為是相鄰的(葉子結點)。

這道題中将樹鍊轉化成線段樹上的結點後,那麼重鍊對應的是一個區間,于是就轉化成了區間修改和單點查詢的問題了。

繼續閱讀