zoukankan      html  css  js  c++  java
  • 洛谷P3178 [HAOI2015]树上操作 题解 树链剖分+线段树

    题目链接:https://www.luogu.org/problem/P3178

    这道题目是一道树链剖分的模板题。
    但是在解决这道问题的同事刷新了我的两个认识:

    第一个认识是:树链剖分不光可以处理链,还可以处理 子树 ,因为:
    节点 u 的子树中所有的点的编号都覆盖在 seg[u]seg[u]+size[u]-1 这个区间内!

    第二个认识是:线段树延迟操作的延迟标记不是标记自己,也就是说:
    lazy[rt] 并不是标记本身的延迟值,而是说 rt 本身有多少个延迟值没有传递给 rt<<1rt<<1|1 的。

    然后这道题目就是一道裸树链剖分题,运用到了子树更新和延迟操作。
    实现代码如下:

    #include <bits/stdc++.h>
    using namespace std;
    #define INF (1<<29)
    const int maxn = 100010;
    int fa[maxn],
    	dep[maxn],
    	size[maxn],
    	son[maxn],
    	top[maxn],
    	seg[maxn], seg_cnt,
    	rev[maxn],
    	n, w[maxn];
    long long sumv[maxn<<2], lazy[maxn<<2];
    vector<int> g[maxn];
    void dfs1(int u, int p) {
    	size[u] = 1;
    	for (vector<int>::iterator it = g[u].begin(); it != g[u].end(); it ++) {
    		int v = (*it);
    		if (v == p) continue;
    		fa[v] = u;
    		dep[v] = dep[u] + 1;
    		dfs1(v, u);
    		size[u] += size[v];
    		if (size[v] >size[son[u]]) son[u] = v;
    	}
    }
    void dfs2(int u, int tp) {
    	seg[u] = ++seg_cnt;
    	rev[seg_cnt] = u;
    	top[u] = tp;
    	if (son[u]) dfs2(son[u], tp);
    	for (vector<int>::iterator it = g[u].begin(); it != g[u].end(); it ++) {
    		int v = (*it);
    		if (v == fa[u] || v == son[u]) continue;
    		dfs2(v, v);
    	}
    }
    #define lson l, mid, rt<<1
    #define rson mid+1, r, rt<<1|1
    void push_down(int rt, int len) {
    	if (lazy[rt]) {
    		int l_len=len-len/2, r_len = len/2;
    		lazy[rt<<1] += lazy[rt];
    		lazy[rt<<1|1] += lazy[rt];
    		sumv[rt<<1] += lazy[rt] * l_len;
    		sumv[rt<<1|1] += lazy[rt] * r_len;
    		lazy[rt] = 0;
    	}
    }
    void push_up(int rt) {
    	sumv[rt] = sumv[rt<<1] + sumv[rt<<1|1];
    }
    void build(int l, int r, int rt) {
    	int mid = (l + r) / 2;
    	if (l == r) {
    		sumv[rt] = w[rev[l]];
    		return;
    	}
    	build(lson); build(rson);
    	push_up(rt);
    }
    void update(int L, int R, long long v, int l, int r, int rt) {
    	if (L <= l && r <= R) {
    		sumv[rt] += (r-l+1) * v;
    		lazy[rt] += v;
    		return;
    	}
    	push_down(rt, r-l+1);
    	int mid = (l + r) / 2;
    	if (L <= mid) update(L, R, v, lson);
    	if (R > mid) update(L, R, v, rson);
    	push_up(rt);
    }
    long long query_sum(int L, int R, int l, int r, int rt) {
    	if (L <= l && r <= R) return sumv[rt];
    	push_down(rt, r-l+1);
    	int mid = (l + r) / 2;
    	long long tmp = 0;
    	if (L <= mid) tmp += query_sum(L, R, lson);
    	if (R > mid) tmp += query_sum(L, R, rson);
    	return tmp;
    }
    long long ask_sum(int u, int v) {
    	long long res = 0;
    	while (top[u] != top[v]) {
    		if (dep[top[u]] < dep[top[v]]) swap(u, v);
    		res += query_sum(seg[top[u]], seg[u], 1, n, 1);
    		u = fa[top[u]];
    	}
    	if (dep[u] < dep[v]) swap(u, v);
    	res += query_sum(seg[v], seg[u], 1, n, 1);
    	return res;
    }
    int m, op, x, a;
    string s;
    int main() {
    	cin >> n >> m;
    	for (int i = 1; i <= n; i ++) cin >> w[i];
    	for (int i = 1; i < n; i ++) {
    		int u, v;
    		cin >> u >> v;
    		g[u].push_back(v);
    		g[v].push_back(u);
    	}
    	dep[1] = fa[1] = 1;
    	dfs1(1, -1);
    	dfs2(1, 1);
    	build(1, n, 1);
    	while (m --) {
    		cin >> op;
    		if (op == 1) {
    			cin >> x >> a;
    			update(seg[x], seg[x], a, 1, n, 1);
    		}
    		else if (op == 2) {
    			cin >> x >> a;
    			update(seg[x], seg[x]+size[x]-1, a, 1, n, 1);
    		}
    		else {
    			cin >> x;
    			cout << ask_sum(1, x) << endl;
    		}
    	}
    	return 0;
    }
    

    作者:zifeiy

  • 相关阅读:
    Best Time to Buy and Sell Stock
    Remove Nth Node From End of List
    Unique Paths
    Swap Nodes in Pairs
    Convert Sorted Array to Binary Search Tree
    Populating Next Right Pointers in Each Node
    Maximum Subarray
    Climbing Stairs
    Unique Binary Search Trees
    Remove Duplicates from Sorted Array
  • 原文地址:https://www.cnblogs.com/codedecision/p/11773779.html
Copyright © 2011-2022 走看看