树链剖分-模板题 HAOI2015

Posted 1218ghcred

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了树链剖分-模板题 HAOI2015相关的知识,希望对你有一定的参考价值。

  1 #include <stdio.h>
  2 #include <vector>
  3 
  4 using namespace std;
  5 
  6 typedef long long LL;
  7 
  8 const int _N = 1000000;
  9 
 10 vector<LL> G[_N];
 11 LL Size[_N], ID[_N], Anc[_N], Hson[_N], D[_N], Dad[_N], A[_N];
 12 LL Seg_root, Seg_cnt, L[_N], R[_N], Sum[_N], Lazy[_N];//segt
 13 LL N, ID_cnt;
 14 
 15 void Find(LL node, LL dad, LL deep)
 16 {
 17     LL mx = -1;
 18     Size[node] = 1, D[node] = deep, Dad[node] = dad;
 19     for (LL i = 0; i != G[node].size(); ++i) {
 20         LL v = G[node][i];
 21         if (v == dad) continue;
 22         Find(v, node, deep + 1), Size[node] += Size[v];
 23         if (mx == -1 || Size[G[node][mx]] < Size[v]) mx = i;
 24     }
 25     if (mx != -1) Hson[node] = G[node][mx];
 26     return;
 27 }
 28 
 29 void Connect(LL node, LL anc)
 30 {
 31     ID[node] = ++ID_cnt, Anc[node] = anc;
 32     if (Hson[node]) Connect(Hson[node], anc);
 33     for (LL i = 0; i != G[node].size(); ++i) {
 34         LL v = G[node][i];
 35         if (v == Dad[node] || v == Hson[node]) continue;
 36         Connect(v, v);
 37     }
 38     return;
 39 }
 40 
 41 void Seg_PD(LL &p, LL l, LL r)
 42 {
 43     if (l == r) { Lazy[p] = 0; return; }
 44     
 45     if (!L[p]) L[p] = ++Seg_cnt;
 46     if (!R[p]) R[p] = ++Seg_cnt;
 47     LL mid = l+r >> 1;
 48     Sum[L[p]] += Lazy[p] * (mid-l+1), Lazy[L[p]] += Lazy[p];
 49     Sum[R[p]] += Lazy[p] * (r-mid), Lazy[R[p]] += Lazy[p];
 50     Lazy[p] = 0;
 51     return;
 52 }
 53 
 54 void Seg_Add(LL &p, LL l, LL r, LL s, LL t, LL d)
 55 {
 56     if (!p) p = ++Seg_cnt;
 57     if (s <= l && r <= t) { Sum[p] += d * (r-l+1), Lazy[p] += d; return; }
 58     LL mid = l+r >> 1;
 59     if (Lazy[p]) Seg_PD(p, l, r);
 60     if (s <= r && t > mid) Seg_Add(R[p], mid+1, r, s, t, d);
 61     if (s <= mid && t >= l) Seg_Add(L[p], l, mid, s, t, d);
 62     Sum[p] = Sum[R[p]] + Sum[L[p]];
 63     return;
 64 }
 65 
 66 LL Seg_Qry(LL &p, LL l, LL r, LL s, LL t)
 67 {
 68     if (!p) p = ++Seg_cnt;
 69     if (s <= l && r <= t) return Sum[p];
 70     LL mid = l+r >> 1, sum = 0;
 71     if (Lazy[p]) Seg_PD(p, l, r);
 72     if (s <= r && t > mid) sum += Seg_Qry(R[p], mid+1, r, s, t);
 73     if (s <= mid && t >= l) sum += Seg_Qry(L[p], l, mid, s, t);
 74     return sum;
 75 }
 76 
 77 void Add_s(LL k, LL d)
 78 {
 79     Seg_Add(Seg_root, 1, N, ID[k], ID[k], d);
 80     return;
 81 }
 82 
 83 void Add_r(LL k, LL d)
 84 {
 85     Seg_Add(Seg_root, 1, N, ID[k], ID[k] + Size[k] - 1, d);
 86     return;
 87 }
 88 
 89 LL Qry(LL x, LL y)
 90 {
 91     LL sum = 0;
 92     while (Anc[x] != Anc[y]) {
 93         if (D[Anc[x]] < D[Anc[y]]) swap(x, y);
 94         sum += Seg_Qry(Seg_root, 1, N, ID[Anc[x]], ID[x]);
 95         x = Dad[Anc[x]];
 96     }
 97     if (D[x] > D[y]) swap(x, y);
 98     sum += Seg_Qry(Seg_root, 1, N, ID[x], ID[y]);
 99     return sum;
100 }
101 
102 int main_main()
103 {
104     LL M, i;
105     scanf("%lld%lld", &N, &M);
106     for (i = 1; i <= N; ++i) scanf("%lld", &A[i]);
107     for (i = 1; i < N; ++i) {
108         LL t1, t2;
109         scanf("%lld%lld", &t1, &t2);
110         G[t1].push_back(t2), G[t2].push_back(t1);
111     }
112     
113     Find(1, -1218, 1);
114     Connect(1, 1);
115     for (i = 1; i <= N; ++i) Add_s(i, A[i]);
116 
117     for (i = 1; i <= M; ++i) {
118         LL ins, t1, t2;
119         scanf("%lld%lld", &ins, &t1);
120         if (ins == 1) {//add_s
121             scanf("%lld", &t2);
122             Add_s(t1, t2);
123         } else if (ins == 2) {//add_r
124             scanf("%lld", &t2);
125             Add_r(t1, t2);
126         } else if (ins == 3) {//qry
127             printf("%lld\n", Qry(1, t1));
128         }
129     }
130     return 0;
131 }
132 
133 const int main_stack=16;    
134 char my_stack[128<<20];    
135 int main() {    
136   __asm__("movl %%esp, (%%eax);\n"::"a"(my_stack):"memory");    
137   __asm__("movl %%eax, %%esp;\n"::"a"(my_stack+sizeof(my_stack)-main_stack):"%esp");    
138   main_main();    
139   __asm__("movl (%%eax), %%esp;\n"::"a"(my_stack):"%esp");    
140   return 0; //add stack copy copy!!!   
141 } 

 

敲了一个树剖模板,顺便复习了一下动态开点的线段树.

NKOJ需要扩栈!

题目

【HAOI2015】树上操作
时间限制 : - MS   空间限制 : 265536 KB 技术分享图片
评测说明 : 1s
问题描述

 有一棵点数为 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 。

以上是关于树链剖分-模板题 HAOI2015的主要内容,如果未能解决你的问题,请参考以下文章

P3178 [HAOI2015]树上操作 (树链剖分模版题)

BZOJ 4034: [HAOI2015]T2 树链剖分

[HAOI2015]树上操作 -树链剖分

cogs 1963. [HAOI 2015] 树上操作 树链剖分+线段树

[HAOI2015]树上操作(树链剖分)

bzoj 4034: [HAOI2015]树上操作 树链剖分+线段树