zoukankan      html  css  js  c++  java
  • [BZOJ4034][HAOI2015]树上操作

    [BZOJ4034][HAOI2015]树上操作

    试题描述

    有一棵点数为 N 的树,以点 1 为根,且树点有边权。然后有 M 个
    操作,分为三种:
    操作 1 :把某个节点 x 的点权增加 a 。
    操作 2 :把某个节点 x 为根的子树中所有点的点权都增加 a 。
    操作 3 :询问某个节点 x 到根的路径中所有点的点权和。

    输入

    第一行包含两个整数 N, M 。表示点数和操作数。接下来一行 N 个整数,表示树中节点的初始权值。接下来 N-1 
    行每行三个正整数 fr, to , 表示该树中存在一条边 (fr, to) 。再接下来 M 行,每行分别表示一次操作。其中
    第一个数表示该操作的种类( 1-3 ) ,之后接这个操作的参数( x 或者 x a ) 。

    输出

    对于每个询问操作,输出该询问的答案。答案之间用换行隔开。

    输入示例

    5 5
    1 2 3 4 5
    1 2
    1 4
    2 3
    2 5
    3 3
    1 2 1
    3 5
    2 1 2
    3 3

    输出示例

    6
    9
    13

    数据规模及约定

    对于 100% 的数据, N,M<=100000 ,且所有输入数据的绝对值都不会超过 10^6 。

    题解

    树链剖分 + 线段树搞一搞就好啦。

    #include <iostream>
    #include <cstdio>
    #include <cstdlib>
    #include <cstring>
    #include <cctype>
    #include <algorithm>
    using namespace std;
    
    int read() {
    	int x = 0, f = 1; char c = getchar();
    	while(!isdigit(c)){ if(c == '-') f = -1; c = getchar(); }
    	while(isdigit(c)){ x = x * 10 + c - '0'; c = getchar(); }
    	return x * f;
    }
    
    #define maxn 100010
    #define maxm 200010
    #define LL long long
    
    int n, m, head[maxn], nxt[maxm], to[maxm];
    LL val[maxn], Val[maxn];
    
    void AddEdge(int a, int b) {
    	to[++m] = b; nxt[m] = head[a]; head[a] = m;
    	swap(a, b);
    	to[++m] = b; nxt[m] = head[a]; head[a] = m;
    	return ;
    }
    
    int fa[maxn], son[maxn], siz[maxn], top[maxn], clo, dl[maxn], dr[maxn];
    void build(int u) {
    	siz[u] = 1;
    	for(int e = head[u]; e; e = nxt[e]) if(to[e] != fa[u]) {
    		fa[to[e]] = u;
    		build(to[e]);
    		siz[u] += siz[to[e]];
    		if(!son[u] || siz[son[u]] < siz[to[e]]) son[u] = to[e];
    	}
    	return ;
    }
    void gett(int u, int tp) {
    	top[u] = tp; dl[u] = ++clo;
    	if(son[u]) gett(son[u], tp);
    	for(int e = head[u]; e; e = nxt[e]) if(to[e] != fa[u] && to[e] != son[u]) gett(to[e], to[e]);
    	dr[u] = clo;
    	return ;
    }
    
    LL addv[maxn<<2], sumv[maxn<<2];
    void maintain(int o, int l, int r) {
    	int lc = o << 1, rc = lc | 1;
    	sumv[o] = sumv[lc] + sumv[rc] + addv[o] * (r - l + 1);
    	return ;
    }
    void build(int o, int l, int r) {
    	if(l == r) sumv[o] = Val[l];
    	else {
    		int mid = l + r >> 1, lc = o << 1, rc = lc | 1;
    		build(lc, l, mid); build(rc, mid + 1, r);
    		maintain(o, l, r);
    	}
    	return ;
    }
    void pushdown(int o, int l, int r) {
    	int mid = l + r >> 1, lc = o << 1, rc = lc | 1;
    	if(l == r){ addv[o] = 0; return ; }
    	addv[lc] += addv[o]; addv[rc] += addv[o];
    	sumv[lc] += addv[o] * (mid - l + 1); sumv[rc] += addv[o] * (r - mid);
    	addv[o] = 0;
    	return ;
    }
    void update(int o, int l, int r, int ql, int qr, int v) {
    	pushdown(o, l, r);
    	if(ql <= l && r <= qr) {
    		addv[o] += v;
    		sumv[o] += (LL)(r - l + 1) * v;
    		return ;
    	}
    	int mid = l + r >> 1, lc = o << 1, rc = lc | 1;
    	if(ql <= mid) update(lc, l, mid, ql, qr, v);
    	if(qr > mid) update(rc, mid + 1, r, ql, qr, v);
    	return maintain(o, l, r);
    }
    LL query(int o, int l, int r, int ql, int qr) {
    	pushdown(o, l, r);
    	if(ql <= l && r <= qr) return sumv[o];
    	int mid = l + r >> 1, lc = o << 1, rc = lc | 1; LL ans = 0;
    	if(ql <= mid) ans += query(lc, l, mid, ql, qr);
    	if(qr > mid) ans += query(rc, mid + 1, r, ql, qr);
    	return ans;
    }
    
    LL ask(int u) {
    	LL ans = 0;
    	while(u) {
    		int f = top[u];
    		ans += query(1, 1, n, dl[f], dl[u]);
    		u = fa[f];
    	}
    	return ans;
    }
    
    int main() {
    	n = read(); int q = read();
    	for(int i = 1; i <= n; i++) val[i] = read();
    	for(int i = 1; i < n; i++) {
    		int a = read(), b = read();
    		AddEdge(a, b);
    	}
    	
    	build(1);
    	gett(1, 1);
    	for(int i = 1; i <= n; i++) Val[dl[i]] = val[i];
    	build(1, 1, n);
    	while(q--) {
    		int tp = read(), u = read();
    		if(tp == 1) {
    			int v = read();
    			update(1, 1, n, dl[u], dl[u], v);
    		}
    		if(tp == 2) {
    			int v = read();
    			update(1, 1, n, dl[u], dr[u], v);
    		}
    		if(tp == 3) printf("%lld
    ", ask(u));
    	}
    	
    	return 0;
    }
    
  • 相关阅读:
    Dynamics CRM The difference between UserId and InitiatingUserId in Plugin
    Dynamics CRM2013 6.1.1.1143版本插件注册器的一个bug
    Dynamics CRM2013 从subgrid中打开快速创建窗体创建数据
    求逆元 HDU1576
    多个数的最小公倍数 HDU1019
    快速幂 HDU3003
    扩展欧几里德算法求逆元1
    筛法求素数 函数模板
    矩阵模板
    快速幂取模函数 递归模板
  • 原文地址:https://www.cnblogs.com/xiao-ju-ruo-xjr/p/6586813.html
Copyright © 2011-2022 走看看