BZOJ2836 魔法树

题意:树上进行两种操作:

(1)链上+d

(2)子树求和

直接链剖即可,子树求和就dfs序即可。

注意,dfs序按照重儿子在最先的序列,然后建立线段树。

  1 /**************************************************************
  2     Problem: 2836
  3     User: rausen
  4     Language: C++
  5     Result: Accepted
  6     Time:4180 ms
  7     Memory:20264 kb
  8 ****************************************************************/
  9
 10 #include <cstdio>
 11 #include <algorithm>
 12
 13 using namespace std;
 14 typedef long long ll;
 15
 16 const int N = 100005;
 17
 18 struct edge {
 19   int next, to;
 20   edge() {}
 21   edge(int _n, int _t) : next(_n), to(_t) {}
 22 } e[N];
 23
 24 struct tree_node {
 25   int fa, son, sz, dep, st, ed, top;
 26 } tr[N];
 27
 28 struct seg_node {
 29   seg_node *ls, *rs;
 30   int len;
 31   ll v, tag;
 32 } *root, mempool[N << 2], *cnt_seg = mempool, *null;
 33
 34 int n, Q;
 35 int first[N], tot, cnt_q;
 36
 37 int read() {
 38   int x = 0;
 39   char ch = getchar();
 40   while (ch < ‘0‘ || ‘9‘ < ch)
 41     ch = getchar();
 42   while (‘0‘ <= ch && ch <= ‘9‘)
 43     (x *= 10) += ch - ‘0‘, ch = getchar();
 44   return x;
 45 }
 46
 47 inline void add_edge(int x, int y) {
 48   e[++tot] = edge(first[x], y);
 49   first[x] = tot;
 50 }
 51
 52 #define y e[x].to
 53 #define Son tr[p].son
 54 void dfs(int p) {
 55   int x;
 56   tr[p].sz = 1;
 57   for (x = first[p]; x; x = e[x].next) {
 58     tr[y].dep = tr[p].dep + 1;
 59     dfs(y);
 60     tr[p].sz += tr[y].sz;
 61     if (Son == 0 || tr[y].sz > tr[Son].sz)
 62       Son = y;
 63   }
 64 }
 65
 66 void DFS(int p) {
 67   int x;
 68   tr[p].st = ++cnt_q;
 69   if (Son) {
 70     tr[Son].top = tr[p].top;
 71     DFS(Son);
 72   }
 73   for (x = first[p]; x; x = e[x].next)
 74     if (y != Son) {
 75       tr[y].top = y;
 76       DFS(y);
 77     }
 78   tr[p].ed = cnt_q;
 79 }
 80 #undef y
 81 #undef Son
 82
 83 #define mid (l + r >> 1)
 84 #define Ls p -> ls
 85 #define Rs p -> rs
 86 #define V p -> v
 87 #define Tag p -> tag
 88 #define Len p -> len
 89 inline void push_tag(seg_node *p) {
 90   Ls -> tag += Tag, Rs -> tag += Tag;
 91   Ls -> v += 1ll * Tag * Ls -> len, Rs -> v += 1ll * Tag * Rs -> len;
 92   Tag = 0;
 93 }
 94
 95 inline void update(seg_node *p) {
 96   V = Ls -> v + Rs -> v;
 97 }
 98
 99 void seg_build(seg_node *&p, int l, int r) {
100   p = ++cnt_seg, Ls = Rs = null;
101   Len = r - l + 1;
102   V = Tag = 0;
103   if (l == r) return;
104   seg_build(Ls, l, mid), seg_build(Rs, mid + 1, r);
105 }
106
107 void seg_modify(seg_node *p, int l, int r, int L, int R, int d) {
108   if (l == L && R == r) {
109     Tag += d, V += 1ll * Len * d;
110     return;
111   }
112   push_tag(p);
113   if (L <= mid) seg_modify(Ls, l, mid, L, min(mid, R), d);
114   if (mid < R) seg_modify(Rs, mid + 1, r, max(mid + 1, L), R, d);
115   update(p);
116 }
117
118 ll seg_query(seg_node *p, int l, int r, int L, int R) {
119   if (l == L && R == r)
120     return V;
121   push_tag(p);
122   ll res = 0;
123   if (L <= mid) res += seg_query(Ls, l, mid, L, min(mid, R));
124   if (mid < R) res += seg_query(Rs, mid + 1, r, max(mid + 1, L), R);
125   return res;
126 }
127 #undef mid
128 #undef Ls
129 #undef Rs
130 #undef V
131 #undef Tag
132 #undef Len
133
134 void work_add(int x, int y, int d) {
135   while (tr[x].top != tr[y].top) {
136     if (tr[tr[x].top].dep < tr[tr[y].top].dep) swap(x, y);
137     seg_modify(root, 1, n, tr[tr[x].top].st, tr[x].st, d);
138     x = tr[tr[x].top].fa;
139   }
140   if (tr[x].dep < tr[y].dep) swap(x, y);
141   seg_modify(root, 1, n, tr[y].st, tr[x].st, d);
142 }
143
144 int main() {
145   int i, x, y, d, oper;
146   null = cnt_seg;
147   null -> ls = null -> rs = null;
148   n = read();
149   for (i = 1; i < n; ++i) {
150     x = read() + 1, y = read() + 1;
151     tr[y].fa = x;
152     add_edge(x, y);
153   }
154   dfs(1);
155   tr[1].top = 1;
156   DFS(1);
157   seg_build(root, 1, n);
158   Q = read();
159   while (Q--) {
160     oper = getchar();
161     while (oper != ‘A‘ && oper != ‘Q‘) oper = getchar();
162     if (oper == ‘A‘) {
163       x = read() + 1, y = read() + 1, d = read();
164       work_add(x, y, d);
165     }
166     else {
167       x = read() + 1;
168       printf("%lld\n", seg_query(root, 1, n, tr[x].st, tr[x].ed));
169     }
170   }
171   return 0;
172 }

时间: 2024-10-12 16:17:58

BZOJ2836 魔法树的相关文章

【树链剖分】【dfs序】【线段树】bzoj2836 魔法树

这道题告诉我们:树链剖分的重标号就是dfs序. #include<cstdio> #include<algorithm> using namespace std; #define N 100001 #define lson rt<<1,l,m #define rson rt<<1|1,m+1,r typedef long long ll; ll delta[N<<2],sumv[N<<2]; int n,m; int en,v[N],

BZOJ 2836 魔法树

练手. #include<iostream> #include<cstdio> #include<cstring> #include<algorithm> #define maxv 100500 #define maxe 200500 using namespace std; long long n,q,x,y,z,g[maxv],nume=1,dis[maxv],top[maxv],fath[maxv],son[maxv],size[maxv],dfn[m

NOIP 2012 第一试 模拟题 魔法树 solution

题意 Solution 压位+前缀和 1 #include <cstdio> 2 #include <iostream> 3 #include <cmath> 4 #include <algorithm> 5 #define ll int 6 using namespace std; 7 const ll mod=100000007; 8 inline void read(ll &k) 9 { 10 ll f=1;char c=getchar();k

洛谷 3833 SHOI 2012 魔法树

[题解] 树链剖分模板题.. #include<cstdio> #include<algorithm> #include<queue> #define N 500010 #define rg register #define ls (u<<1) #define rs (u<<1|1) #define mid ((a[u].l+a[u].r)>>1) #define len(x) (a[x].r-a[x].l+1) using name

P3833 [SHOI2012]魔法树

简单的树链剖分,自己随便弄个样例就能过. 给你一个树,支持两个操作: 从u点到v点的路径上的点的权值都添加上d. 查询以u点为根的子树的权值和. 唯一可能错的就是1操作了. u到v的路径,显然需要找出他们的lca. 那么就分为两部分:u到lca和lca到v. 但是发现:走这么一段路,dfn不一定连续啊! 所以需要一直用top数组来跳上去,同一条链上的点的dfn是连续的. 后来我发现:可以在找lca的过程中直接完成啊!上下走是一样的. 所以就过了. 代码: #include<cstdio> #i

[SHOI2012]魔法树

题目传送门 省选D2T3考板子可真是不多见呢....~~~ 这题就是一个裸的树链剖分,对于每一个Add操作,维护从u至v的路径,对于每一个Query操作,询问以u为根的子树之和.如果不会树链剖分可以看我的往期博客,具体细节在代码之中就不多赘述了~ 下面给出参考代码: #include<iostream> #include<cstdio> #define N 400005 #define M 800005 #define lc k*2 #define rc k*2+1 #define

cojs 出的题目的总结

最近因为一些事情心情不太好,所以在cojs上出了几套题 (大神不要吐槽太水.. 大部分都是模板题,对模板做个总结吧,等到NOI之前还可以复习复习 今天晚上把疯狂的系列最后一道题目出完了就去切APIO了QAQ 白树黑是数学题+概率算法,不能算模板.. 动态点分治:复仇的序幕曲,树黑白 CDQ分治:决战前的黎明 双连通分量:地牢里的背叛 KD_Tree:Rikka 三分:向量vec 树链剖分:黑白树,黑树白 树上倍增:树黑白,树白黑 主席树:树白黑,黑树白 fib求循环节+矩阵乘法:疯狂的斐波那契

【SDOI2016】生成魔咒

Description 魔咒串由许多魔咒字符组成,魔咒字符可以用数字表示.例如可以将魔咒字符 1.2 拼凑起来形成一个魔咒串 [1,2]. 一个魔咒串 S 的非空字串被称为魔咒串 S 的生成魔咒. 例如 S=[1,2,1] 时,它的生成魔咒有 [1].[2].[1,2].[2,1].[1,2,1] 五种.S=[1,1,1] 时,它的生成魔咒有 [1]. [1,1].[1,1,1] 三种.最初 S 为空串.共进行 n 次操作,每次操作是在 S 的结尾加入一个魔咒字符.每次操作后都 需要求出,当前的

Clang之语法抽象语法树AST

语法分析器的任务是确定某个单词流是否能够与源语言的语法适配,即设定一个称之为上下文无关语言(context-free language)的语言集合,语法分析器建立一颗与(词法分析出的)输入单词流对应的正确语法树.语法分析树的建立过程主要有两种方法:自顶向下语法分析法和自底向上分析法.AST作为语法分析树(parse tree)的一种简写方式,它独立于具体编程语言(C++.Java.C等),而且与语法分析树的建立过程无关(自顶向下和自底向上逻辑等价),是联系编译器前端.后端的重要接口.Clang的