树链剖分

树链剖分是基于重孩子将树划分成若干条链,配上对应的数据结构(例如这里的线段树)就可以维护树中的链,甚至可以直接维护子树。

貌似还有更高级的$\text{LCT}$,要搭配$\text{Splay}$。正在学习中。

具体证明。。待更。。

源码如下。

  1 #include <bits/stdc++.h>
  2 
  3 using namespace std;
  4 
  5 #define re register
  6 #define rep(i, a, b) for (re int i = a; i <= b; ++i)
  7 #define repd(i, a, b) for (re int i = a; i >= b; --i)
  8 #define For(i, a, b, s) for (re int i = a; i <= b; s)
  9 #define maxx(a, b) a = max(a, b)
 10 #define minn(a, b) a = min(a, b)
 11 #define LL long long
 12 #define INF (1 << 30)
 13 
 14 inline int read() {
 15     int w = 0, f = 1; char c = getchar();
 16     while (!isdigit(c)) f = c == '-' ? -1 : f, c = getchar();
 17     while (isdigit(c)) w = (w << 3) + (w << 1) + (c ^ '0'), c = getchar();
 18     return w * f;
 19 }
 20 
 21 const int maxn = 1e5 + 5;
 22 
 23 int N, M, R, P;
 24 
 25 struct Edge {
 26     int u, v, pre;
 27 } e[maxn << 1];
 28 int ec, G[maxn];
 29 void init() { ec = 0; memset(G, -1, sizeof(G)); }
 30 void add(int u, int v) { e[ec++] = (Edge){u, v, G[u]}; G[u] = ec-1; }
 31 #define iter(i, u) for (register int i = G[u]; i != -1; i = e[i].pre)
 32 // 
 33 
 34 int a[maxn], val[maxn]; // a按照下文mark的顺序
 35 struct SegT {
 36 #define lson (o << 1)
 37 #define rson (o << 1 | 1)
 38     int sumv[maxn << 4], tag[maxn << 4];
 39     void pushup(int o) { sumv[o] = sumv[lson] + sumv[rson]; }
 40     void pushdown(int o, int l, int r) {
 41         if (!tag[o]) return;
 42         tag[lson] += tag[o]; tag[rson] += tag[o];
 43         int mid = (l + r) >> 1;
 44         sumv[lson] = (sumv[lson] + (LL)tag[o] * (mid - l + 1)) % P; sumv[rson] = (sumv[rson] + (LL)tag[o] * (r - mid)) % P;
 45         tag[o] = 0;
 46     }
 47     void build(int o, int l, int r) {
 48         if (l == r) { sumv[o] = a[l]; tag[o] = 0; return; }
 49         int mid = (l + r) >> 1;
 50         build(lson, l, mid); build(rson, mid+1, r);
 51         pushup(o);
 52     }
 53     void modify(int o, int l, int r, int ql, int qr, int v) {
 54         if (ql <= l && r <= qr) { sumv[o] = (sumv[o] + (LL)v * (r - l + 1)) % P; tag[o] = (tag[o] + v) % P; return; }
 55         pushdown(o, l, r);
 56         int mid = (l + r) >> 1;
 57         if (ql <= mid) modify(lson, l, mid, ql, qr, v);
 58         if (mid < qr) modify(rson, mid+1, r, ql, qr, v);
 59         pushup(o);
 60     }
 61     int query(int o, int l, int r, int ql, int qr) {
 62         if (ql <= l && r <= qr) return sumv[o];
 63         pushdown(o, l, r);
 64         int mid = (l + r) >> 1; LL res = 0;
 65         if (ql <= mid) res += query(lson, l, mid, ql, qr);
 66         if (mid < qr) res += query(rson, mid+1, r, ql, qr);
 67         return res % P;
 68     }
 69 } T;
 70 
 71 //
 72 int son[maxn], link[maxn], mark[maxn], par[maxn], dep[maxn], topf[maxn], st[maxn], en[maxn], cnt = 0;
 73 // son表示结点i的子树大小(包括i),link表示重孩子,mark表示结点i在线段树的位置,par表示父亲结点,dep表示结点i的深度,topf表示i所在的树链的头,st,ed表示子数所在区间。
 74 void dfs1(int u, int fa) {
 75     son[u] = 1; link[u] = u; dep[u] = dep[fa]+1; par[u] = fa;
 76     iter(i, u)
 77         if (e[i].v != fa) {
 78             dfs1(e[i].v, u);
 79             if (son[e[i].v] >= son[link[u]]) link[u] = e[i].v; // 必须写前面!!否则会挂(因为如果有儿子结点就一定会更新,放后面就不行了)
 80             son[u] += son[e[i].v];
 81         }
 82 }
 83 void dfs2(int u, int fa, int head) {
 84     mark[u] = st[u] = ++cnt; topf[u] = head; a[cnt] = val[u];
 85     if (link[u] != u) dfs2(link[u], u, head);
 86     iter(i, u)
 87         if (e[i].v != fa && e[i].v != link[u])
 88             dfs2(e[i].v, u, e[i].v);
 89     en[u] = cnt;
 90 }
 91 #define swap(i, j) i ^= j ^= i ^= j;
 92 void modify_link(int x, int y, int v) {
 93     while (topf[x] != topf[y]) {
 94         if (dep[topf[x]] < dep[topf[y]]) swap(x, y);
 95         T.modify(1, 1, N, mark[topf[x]], mark[x], v);
 96         x = par[topf[x]];
 97     }
 98     if (dep[x] > dep[y]) swap(x, y);
 99     T.modify(1, 1, N, mark[x], mark[y], v);
100 }
101 int query_link(int x, int y) {
102     LL res = 0;
103     while (topf[x] != topf[y]) {
104         if (dep[topf[x]] < dep[topf[y]]) swap(x, y);
105         res += T.query(1, 1, N, mark[topf[x]], mark[x]);
106         x = par[topf[x]];
107     }
108     if (dep[x] > dep[y]) swap(x, y);
109     return (res + T.query(1, 1, N, mark[x], mark[y])) % P;
110 }
111 void modify_tree(int x, int v) { T.modify(1, 1, N, st[x], en[x], v); }
112 int query_tree(int x) { return T.query(1, 1, N, st[x], en[x]); }
113 // ###
114 
115 int opt, x, y, z;
116 
117 int main() {
118     init();
119     N = read(), M = read(), R = read(), P = read();
120     rep(i, 1, N) val[i] = read();
121     rep(i, 1, N-1) {
122         x = read(), y = read();
123         add(x, y); add(y, x);
124     }
125     dfs1(R, R); dfs2(R, R, R); T.build(1, 1, N);
126     rep(i, 1, M) {
127         opt = read();
128         if (opt == 1) {
129             x = read(), y = read(), z = read();
130             modify_link(x, y, z);
131         }
132         else if (opt == 4) {
133             x = read();
134             printf("%d\n", query_tree(x));
135         } else {
136             x = read(), y = read();
137             if (opt == 2) printf("%d\n", query_link(x, y));
138             else modify_tree(x, y);
139         }
140     }
141     return 0;
142 }

 

posted @ 2019-02-24 13:24  AC-Evil  阅读(137)  评论(0编辑  收藏  举报