BZOJ4034 [HAOI2015]T2

本来直接树剖就好了,但是树剖会多一个log非常不开心

我们来考虑维护dfs序,那么序列上的每个元素表示该点的答案

单点点权修改操作就是dfs序上段加操作

子树修改操作就是dfs序上段减一个数,然后每个点加上固定值乘以它的深度

具体的来讲。。。dfs序上每个点维护三个东西,叫v,tag和times,分别表示当前值,区间的加减,每个点的深度

单点修改就是v += d,而子树修改就是tag += d

于是用线段树维护就好了

  1 /**************************************************************
  2     Problem: 4034
  3     User: rausen
  4     Language: C++
  5     Result: Accepted
  6     Time:1128 ms
  7     Memory:21796 kb
  8 ****************************************************************/
  9
 10 #include <cstdio>
 11
 12 using namespace std;
 13 typedef long long ll;
 14 const int N = 1e5 + 5;
 15 const int Maxlen = N * 50;
 16
 17 inline int read();
 18 inline void print(ll);
 19
 20 struct edge {
 21     int next, to;
 22     edge(int _n = 0, int _t = 0) : next(_n), to(_t) {}
 23 } e[N << 1];
 24
 25 int first[N], tot;
 26
 27 struct seg {
 28     seg *ls, *rs;
 29     int times;
 30     ll v, tag;
 31
 32     seg() {
 33         ls = rs = NULL;
 34         v = tag = times = 0;
 35     }
 36
 37     #define Len (1 << 16)
 38     inline void* operator new(size_t) {
 39         static seg *mempool, *c;
 40         if (c == mempool)
 41             mempool = (c = new seg[Len]) + Len;
 42         *c = seg();
 43         return c++;
 44     }
 45     #undef Len
 46
 47     inline void push() {
 48         if (v) {
 49             if (ls) ls -> v += v;
 50             if (rs) rs -> v += v;
 51             v = 0;
 52         }
 53         if (tag) {
 54             if (ls) ls -> tag += tag;
 55             if (rs) rs -> tag += tag;
 56             tag = 0;
 57         }
 58     }
 59
 60     #define mid (l + r >> 1)
 61     void build(int l, int r, ll *a, int *b) {
 62         if (l == r) {
 63             v = a[l], times = b[l];
 64             return;
 65         }
 66         ls = new()seg, rs = new()seg;
 67         ls -> build(l, mid, a, b), rs -> build(mid + 1, r, a, b);
 68     }
 69
 70     void modify(int l, int r, int L, int R, int d) {
 71         if (L <= l && r <= R) {
 72             v += d;
 73             return;
 74         }
 75         push();
 76         if (L <= mid) ls -> modify(l, mid, L, R, d);
 77         if (mid < R) rs -> modify(mid + 1, r, L, R, d);
 78     }
 79
 80     void Modify(int l, int r, int L, int R, int dep, int d) {
 81         if (L <= l && r <= R) {
 82             v -= 1ll * d * (dep - 1), tag += d;
 83             return;
 84         }
 85         push();
 86         if (L <= mid) ls -> Modify(l, mid, L, R, dep, d);
 87         if (mid < R) rs -> Modify(mid + 1, r, L, R, dep, d);
 88     }
 89
 90     ll query(int l, int r, int pos) {
 91         if (l == r) return v + tag * times;
 92         push();
 93         if (pos <= mid) return ls -> query(l, mid, pos);
 94         return rs -> query(mid + 1, r, pos);
 95     }
 96     #undef mid
 97 } *T;
 98
 99 struct tree_node {
100     int fa, v, dep;
101     int st, ed;
102 } tr[N];
103
104 int n, m, cnt_seq;
105 ll a[N];
106 int b[N];
107
108 char buf[Maxlen], *c = buf;
109 int Len;
110
111 inline void Add_Edges(int x, int y) {
112     e[++tot] = edge(first[x], y), first[x] = tot;
113     e[++tot] = edge(first[y], x), first[y] = tot;
114 }
115
116 #define y e[x].to
117 void dfs(int p) {
118     int x;
119     a[tr[p].st = ++cnt_seq] = a[tr[tr[p].fa].st] + tr[p].v;
120     b[cnt_seq] = tr[p].dep;
121     for (x = first[p]; x; x = e[x].next)
122         if (y != tr[p].fa) {
123             tr[y].fa = p, tr[y].dep = tr[p].dep + 1;
124             dfs(y);
125         }
126     tr[p].ed = cnt_seq;
127 }
128 #undef y
129
130 int main() {
131     Len = fread(c, 1, Maxlen, stdin);
132     buf[Len] = ‘\0‘;
133     int i, oper, x;
134     n = read(), m = read();
135     for (i = 1; i <= n; ++i) tr[i].v = read();
136     for (i = 1; i < n; ++i)
137         Add_Edges(read(), read());
138     dfs(1);
139     T = new()seg;
140     T -> build(1, n, a, b);
141     while (m--) {
142         oper = read(), x = read();
143         if (oper == 1) T -> modify(1, n, tr[x].st, tr[x].ed, read());
144         if (oper == 2) T -> Modify(1, n, tr[x].st, tr[x].ed, tr[x].dep, read());
145         if (oper == 3) print(T -> query(1, n, tr[x].st));
146     }
147     return 0;
148 }
149
150 inline int read() {
151     static int x, sgn;
152     x = 0, sgn = 1;
153     while (*c < ‘0‘ || ‘9‘ < *c) {
154         if (*c == ‘-‘) sgn = -1;
155         ++c;
156     }
157     while (‘0‘ <= *c && *c <= ‘9‘)
158         x = x * 10 + *c - ‘0‘, ++c;
159     return sgn * x;
160 }
161
162 inline void print(ll t) {
163     int tot = 0, pr[25];
164     if (t < 0) putchar(‘-‘), t = -t;
165     tot = 0;
166     while (t)
167         pr[++tot] = t % 10, t /= 10;
168     if (!tot) putchar(‘0‘);
169     while (tot) putchar(pr[tot--] + ‘0‘);
170     putchar(‘\n‘);
171 }

时间: 2024-10-03 12:13:08

BZOJ4034 [HAOI2015]T2的相关文章

BZOJ 4034: [HAOI2015]T2 树链剖分

4034: [HAOI2015]T2 Description 有一棵点数为 N 的树,以点 1 为根,且树点有边权.然后有 M 个 操作,分为三种: 操作 1 :把某个节点 x 的点权增加 a . 操作 2 :把某个节点 x 为根的子树中所有点的点权都增加 a . 操作 3 :询问某个节点 x 到根的路径中所有点的点权和. Input 第一行包含两个整数 N, M .表示点数和操作数. 接下来一行 N 个整数,表示树中节点的初始权值. 接下来 N-1 行每行三个正整数 fr, to , 表示该树

数据结构(树链剖分):BZOJ 4034: [HAOI2015]T2

Description 有一棵点数为 N 的树,以点 1 为根,且树点有边权.然后有 M 个 操作,分为三种: 操作 1 :把某个节点 x 的点权增加 a . 操作 2 :把某个节点 x 为根的子树中所有点的点权都增加 a . 操作 3 :询问某个节点 x 到根的路径中所有点的点权和. Input 第一行包含两个整数 N, M .表示点数和操作数. 接下来一行 N 个整数,表示树中节点的初始权值. 接下来 N-1 行每行三个正整数 fr, to , 表示该树中存在一条边 (fr, to) . 再

bzoj千题计划242:bzoj4034: [HAOI2015]树上操作

http://www.lydsy.com/JudgeOnline/problem.php?id=4034 dfs序,树链剖分 #include<cstdio> #include<iostream> using namespace std; #define N 100001 typedef long long LL; int n,a[N]; int front[N],nxt[N<<1],to[N<<1],tot; int fa[N],siz[N],dep[N]

bzoj4034: [HAOI2015]树上操作(树剖)

4034: [HAOI2015]树上操作 题目:传送门 题解: 树剖裸题: 麻烦一点的就只有子树修改(其实一点也不),因为子树编号连续啊,直接改段(记录编号最小和最大) 开个long long 水模版 代码: 1 #include<cstdio> 2 #include<cstring> 3 #include<cstdlib> 4 #include<cmath> 5 #include<algorithm> 6 using namespace std

bzoj 4034: [HAOI2015]T2

树刨 一定要注意long long 1 #include<cstdio> 2 #include<iostream> 3 #include<cstring> 4 #include<cstdlib> 5 #include<cmath> 6 #include<queue> 7 #include<algorithm> 8 #include<vector> 9 #define M 2000009 10 #define E

[HAOI2015]T2

[题目描述] 有一棵点数为N的树,以点1为根,且树点有边权.然后有M个操作,分为三种: 操作1:把某个节点x的点权增加a. 操作2:把某个节点x为根的子树中所有点的点权都增加a. 操作3:询问某个节点x到根的路径中所有点的点权和. [输入格式] 第一行两个整数N,M,表示点数和操作数. 接下来一行N个整数,表示树中节点的初始权值. 接下来N-1行每行两个正整数fr,to,表示该树中存在一条边(fr,to). 再接下来M行,每行分别表示一次操作.其中第一个数表示该操作的种类(1~3),之后接这个操

BZOJ 4034 [HAOI2015]T2 树链剖分+线段树

题意: 一棵以1为根的树,有n个节点,m个操作. 第一种单点修改. 第二种修改一个点的子树. 第三种询问一个点到根的路径上所有点的权值和. 解析: 看到有人在做我就跑过来看了一下,看完题发现这不SB题么- - 于是就写了下,差点被出题人气死. TMD 那个 fr , to 难道就是逗我玩的? 你丫fr,to不代表有向边? 这么出题不会掉RP? 改了20分钟就这错了?你逗我? 第一种操作略 第二种操作修改子树-dfs序. 第三种链剖完之后直接找就行了. 复杂度O(nlog^2n); 代码: #in

[BZOJ4034][HAOI2015]树上操作

题目描述 Description 有一棵点数为 N 的树,以点 1 为根,且树点有边权.然后有 M 个 操作,分为三种: 操作 1 :把某个节点 x 的点权增加 a . 操作 2 :把某个节点 x 为根的子树中所有点的点权都增加 a . 操作 3 :询问某个节点 x 到根的路径中所有点的点权和. 输入描述 Input Description 第一行包含两个整数 N, M .表示点数和操作数.接下来一行 N 个整数,表示树中节点的初始权值.接下来 N-1 行每行三个正整数 fr, to , 表示该

JZYZOJ1539[haoi2015]T2 树链剖分

http://172.20.6.3/Problem_Show.asp?id=1539 在学校的OJ又写了一次,RE了好多次,原来haoi的时候这道题需要开栈+快读,裸数据结构30分,加上快读50分.oi考试的时候原来不能汇编开栈,只能写手工栈orz,学长说当时省选最高分50,本来以为很简单的题没想到这么套路. 代码 1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 #include<algo