zoukankan      html  css  js  c++  java
  • [洛谷P3178][HAOI2015]树上操作

    题目大意:有一棵点数为 $N$ 的树,以点 1 为根。然后有 $M$ 个操作。

    1. 把 $x$ 的点权增加 $a$ 。

    2. 把 $x$ 为根的子树中所有点的点权都增加 $a$ 。

    3. 询问 $x$ 到根的路径中所有点的点权和。

    题解:树链剖分模板题

    卡点:我真的好久没打树剖了。。。

    1.线段树$tag$写错

    2.树剖$query$打错

    3.一堆东西没开$long ; long$

    C++ Code:

    #include <cstdio>
    #define maxn 100010
    using namespace std;
    int n, m, S[maxn], s[maxn];
    int head[maxn], cnt;
    struct Edge {
    	int to, nxt;
    } e[maxn << 1];
    void add(int a, int b) {
    	e[++cnt] = (Edge) {b, head[a]}; head[a] = cnt;
    }
    int dfn[maxn], son[maxn], sz[maxn], idx;
    int dep[maxn], fa[maxn], top[maxn];
    void dfs1(int rt) {
    	sz[rt] = 1;
    	for (int i = head[rt]; i; i = e[i].nxt) {
    		int v = e[i].to;
    		if (v != fa[rt]) {
    			dep[v] = dep[rt] + 1;
    			fa[v] = rt;
    			dfs1(v);
    			if (!son[rt] || sz[v] > sz[son[rt]]) son[rt] = v;
    			sz[rt] += sz[v];
    		}
    	}
    }
    void dfs2(int rt) {
    	dfn[rt] = ++idx;
    	int v = son[rt];
    	if (v) top[v] = top[rt], dfs2(v);
    	for (int i = head[rt]; i; i = e[i].nxt) {
    		v = e[i].to;
    		if (v != fa[rt] && v != son[rt]) {
    			top[v] = v;
    			dfs2(v);
    		}
    	}
    }
    long long v[maxn << 2], cov[maxn << 2];
    void build(int rt, int l, int r) {
    	if (l == r) {
    		v[rt] = s[l];
    		return ;
    	}
    	int mid = l + r >> 1;
    	build(rt << 1, l, mid);
    	build(rt << 1 | 1, mid + 1, r);
    	v[rt] = v[rt << 1] + v[rt << 1 | 1];
    }
    void pushdown(int rt, int len) {
    	long long &tmp = cov[rt];
    	v[rt << 1] += tmp * (len + 1 >> 1);
    	v[rt << 1 | 1] += tmp * (len >> 1);
    	cov[rt << 1] += tmp;
    	cov[rt << 1 | 1] += tmp;
    	tmp = 0;
    }
    void add(int rt, int l, int r, int L, int R, long long num) {
    	if (L <= l && R >= r) {
    		v[rt] += num * (r - l + 1);
    		cov[rt] += num;
    		return ;
    	}
    	int mid = l + r >> 1;
    	if (cov[rt]) pushdown(rt, r - l + 1);
    	if (L <= mid) add(rt << 1, l, mid, L, R, num);
    	if (R > mid) add(rt << 1 | 1, mid + 1, r, L, R, num);
    	v[rt] = v[rt << 1] + v[rt << 1 | 1];
    }
    long long ask(int rt, int l, int r, int L, int R) {
    	if (L <= l && R >= r) {
    		return v[rt];
    	}
    	int mid = l + r >> 1;
    	long long ans = 0;
    //	printf("%d %d %d %d %d
    ", rt, l, r, L, R);
    	if (cov[rt]) pushdown(rt, r - l + 1);
    	if (L <= mid) ans = ask(rt << 1, l, mid, L, R);
    	if (R > mid) ans += ask(rt << 1 | 1, mid + 1, r, L, R);
    	return ans;
    }
    long long query(int rt) {
    	long long ans = 0;
    	while (top[rt] != 1) {
    		ans += ask(1, 1, n, dfn[top[rt]], dfn[rt]);
    		rt = fa[top[rt]];
    	}
    	ans += ask(1, 1, n, dfn[1], dfn[rt]);
    	return ans;
    }
    int main() {
    	scanf("%d%d", &n, &m);
    	for (int i = 1; i <= n; i++) scanf("%d", &S[i]);
    	for (int i = 1; i < n; i++) {
    		int a, b;
    		scanf("%d%d", &a, &b);
    		add(a, b);
    		add(b, a);
    	}
    	dep[top[1] = 1] = 1;
    	dfs1(1);
    	dfs2(1);
    	for (int i = 1; i <= n; i++) s[dfn[i]] = S[i];
    	build(1, 1, n);
    	int op, a; long long x;
    	while (m--) {
    		scanf("%d%d", &op, &a);
    		if (op == 3) {
    			printf("%lld
    ", query(a));
    		} else {
    			scanf("%lld", &x);
    			if (op == 1) add(1, 1, n, dfn[a], dfn[a], x);
    			else add(1, 1, n, dfn[a], dfn[a] + sz[a] - 1, x);
    		}
    	}
    	return 0;
    }
    

      

  • 相关阅读:
    JDK下载 安装 配置
    C#中的委托与事件 笔记
    转载 -- C# 中的委托和事件
    Laravel5 路由问题 /home页面无法访问
    eclipse的android智能提示设置
    svn在linux下的使用(ubuntu命令行模式操作svn)
    gdb结合coredump定位崩溃进程
    Android帧缓冲区(Frame Buffer)硬件抽象层(HAL)模块Gralloc的实现原理分析
    struct的初始化,拷贝及指针成员的使用技巧
    C++ 资源大全
  • 原文地址:https://www.cnblogs.com/Memory-of-winter/p/9459829.html
Copyright © 2011-2022 走看看