F. A Growing Tree

F. A Growing Tree

看到给子树加和是很容易想到树链剖分的。

这题表面上往树上动态加点,容易让我们觉得直接往子树上加权值会影响还未添加进来的点。

但是我们再仔细考虑一下,实际上当每一个点新加进来的时候,这个点的子树的值都相等,因此每次插入一个新点的时候给这个节点的子树减掉当前的值就相当于新插入一个点了。

由于这题是区间修改单点查询,所以实际上可以用树状数组来差分。

当然也可以使用带懒标记的线段树。

#include <bits/stdc++.h>

using i64 = long long;

struct HLD {
    int n;
    std::vector<int> siz, top, dep, parent, in, out, seq;
    std::vector<std::vector<int>> adj;
    int cur;
    
    HLD() {}
    HLD(int n) {
        init(n);
    }
    void init(int n) {
        this->n = n;
        siz.resize(n);
        top.resize(n);
        dep.resize(n);
        parent.resize(n);
        in.resize(n);
        out.resize(n);
        seq.resize(n);
        cur = 0;
        adj.assign(n, {});
    }
    void addEdge(int u, int v) {
        adj[u].push_back(v);
        adj[v].push_back(u);
    }
    void work(int root = 0) {
        top[root] = root;
        dep[root] = 0;
        parent[root] = -1;
        dfs1(root);
        dfs2(root);
    }
    void dfs1(int u) {
        if (parent[u] != -1) {
            adj[u].erase(std::find(adj[u].begin(), adj[u].end(), parent[u]));
        }
        
        siz[u] = 1;
        for (auto &v : adj[u]) {
            parent[v] = u;
            dep[v] = dep[u] + 1;
            dfs1(v);
            siz[u] += siz[v];
            if (siz[v] > siz[adj[u][0]]) {
                std::swap(v, adj[u][0]);
            }
        }
    }
    void dfs2(int u) {
        in[u] = cur++;
        seq[in[u]] = u;
        for (auto v : adj[u]) {
            top[v] = v == adj[u][0] ? top[u] : v;
            dfs2(v);
        }
        out[u] = cur;
    }
    int lca(int u, int v) {
        while (top[u] != top[v]) {
            if (dep[top[u]] > dep[top[v]]) {
                u = parent[top[u]];
            } else {
                v = parent[top[v]];
            }
        }
        return dep[u] < dep[v] ? u : v;
    }
    
    int dist(int u, int v) {
        return dep[u] + dep[v] - 2 * dep[lca(u, v)];
    }
    
    int jump(int u, int k) {
        if (dep[u] < k) {
            return -1;
        }
        
        int d = dep[u] - k;
        
        while (dep[top[u]] > d) {
            u = parent[top[u]];
        }
        
        return seq[in[u] - dep[u] + d];
    }
    
    bool isAncester(int u, int v) {
        return in[u] <= in[v] && in[v] < out[u];
    }
    
    int rootedParent(int u, int v) {
        std::swap(u, v);
        if (u == v) {
            return u;
        }
        if (!isAncester(u, v)) {
            return parent[u];
        }
        auto it = std::upper_bound(adj[u].begin(), adj[u].end(), v, [&](int x, int y) {
            return in[x] < in[y];
        }) - 1;
        return *it;
    }
    
    int rootedSize(int u, int v) {
        if (u == v) {
            return n;
        }
        if (!isAncester(v, u)) {
            return siz[v];
        }
        return n - siz[rootedParent(u, v)];
    }
    
    int rootedLca(int a, int b, int c) {
        return lca(a, b) ^ lca(b, c) ^ lca(c, a);
    }
};

template <typename T>
struct Fenwick {
    int n;
    std::vector<T> a;
    Fenwick(int n = 0) {
        init(n);
    }
    void init(int n) {
        this->n = n;
        a.assign(n, T());
    }   
    void add(int x, T v) {
        for (int i = x + 1; i <= n; i += i & -i) {
            a[i - 1] += v;
        }
    }    
    T sum(int x) {
        auto ans = T();
        for (int i = x; i > 0; i -= i & -i) {
            ans += a[i - 1];
        }
        return ans;
    }    
    T rangeSum(int l, int r) {
        return sum(r) - sum(l);
    }    
    int kth(T k) {
        int x = 0;
        for (int i = 1 << std::__lg(n); i; i /= 2) {
            if (x + i <= n && k >= a[x + i - 1]) {
                x += i;
                k -= a[x - 1];
            }
        }
        return x;
    }
};

struct Qry {
	int op, v, x;
};
void solve() {
	int n;
	std::cin >> n;

	int idx = 1;
	std::vector<Qry> op(n);
	
	for (int i = 0; i < n; i++) {
		int ins, v, x;
		std::cin >> ins >> v;
		v--;
		if (ins == 1) {
			op[i] = {ins, v, idx++};
		} else {
			int x;
			std::cin >> x;
			op[i] = {ins, v, x};
		}
	}

	HLD t(idx);
	for (auto [ins, v, x] : op) {
		// std::cerr << "instruction: " << ins << " " << v << " " << x << "\n";
		if (ins == 1) {
			// std::cerr << "vertex: " << v << " " << x << "\n";
			t.addEdge(v, x);
		}
	}
	Fenwick<i64> fen(idx);
	t.work();

	for (auto [ins, v, x] : op) {
		if (ins == 1) {
			// i64 val = seg.rangeQuery(t.in[x], t.in[x] + 1).x;
			i64 val = fen.sum(t.in[x] + 1);
			// std::cerr << val << "\n";
			fen.add(t.in[x], -val);
			fen.add(t.out[x], val);
			// seg.rangeApply(t.in[x], t.out[x], {-val});
		} else {
			fen.add(t.in[v], x);
			fen.add(t.out[v], -x);
			// seg.rangeApply(t.in[v], t.out[v], {x});
		}
	}

	for (int i = 0; i < idx; i++) {
		std::cout << fen.sum(t.in[i] + 1) << " \n"[i == idx - 1];
	}
}

int main() {
	std::ios::sync_with_stdio(false);
	std::cin.tie(nullptr);

	int t;
	std::cin >> t;

	while (t--) {
		solve();
	}

	return 0;
}
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值