树链剖分模板
Posted frankscode
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了树链剖分模板相关的知识,希望对你有一定的参考价值。
1 #include<cstdio> 2 #include<iostream> 3 #include<vector> 4 #define tx top[x] 5 #define ty top[y] 6 #define ls o<<1 7 #define rs o<<1|1 8 #define M ((L+R)>>1) 9 using namespace std; 10 const int maxn = 100010; 11 12 int n, m, P ,root, tot; 13 int A[maxn], fa[maxn], deep[maxn], num[maxn], son[maxn], ID[maxn], top[maxn], fID[maxn]; 14 int sumv[maxn*4],addv[maxn*4]; 15 vector<int> G[maxn]; 16 17 void addedge(int x,int y) { 18 G[x].push_back(y); 19 } 20 21 int dfs1(int x,int dep) { //返回包括自己,子树的大小 22 deep[x] = dep; 23 int ret = 1; 24 int len = G[x].size(); 25 int MX = 0; 26 for(int i = 0;i < len;i++) { 27 int tp = G[x][i]; 28 if(fa[x] == tp) continue; 29 fa[tp] = x; 30 int back = dfs1(tp,dep+1); 31 if(back > MX) { 32 son[x] = tp; 33 MX = back; 34 } 35 ret += back; 36 } 37 num[x] = ret; 38 return ret; 39 } 40 41 void dfs2(int x) { 42 if(x == 0) return; 43 ID[x] = ++tot; 44 fID[tot] = x; 45 if(son[fa[x]] == x) top[x] = top[fa[x]]; 46 else top[x] = x; 47 int len = G[x].size(); 48 dfs2(son[x]); 49 for(int i = 0;i < len;i++) { 50 int tp = G[x][i]; 51 if(tp != fa[x] && tp != son[x]) dfs2(tp); 52 } 53 } 54 55 inline void build(int o,int L,int R) { 56 if(L == R) { 57 sumv[o] = A[fID[L]]%P; 58 return; 59 } 60 build(ls,L,M); 61 build(rs,M+1,R); 62 sumv[o] = (sumv[ls] + sumv[rs])%P; 63 } 64 65 inline void pushdown(int o,int L,int R) { 66 (addv[ls] += addv[o])%=P; 67 (addv[rs] += addv[o])%=P; 68 (sumv[ls] += addv[o]*(M-L+1))%=P; 69 (sumv[rs] += addv[o]*(R-M))%=P; 70 addv[o] = 0; 71 } 72 73 int ql,qr,qa; 74 inline void update(int o,int L,int R) { 75 if(ql <= L && R <= qr) { 76 (addv[o] += qa)%=P; 77 (sumv[o] += qa*(R-L+1))%=P; 78 return; 79 } 80 pushdown(o,L,R); 81 if(ql <= M) update(ls,L,M); 82 if(qr > M) update(rs,M+1,R); 83 sumv[o] = (sumv[ls] + sumv[rs])%P; 84 } 85 86 inline int query(int o,int L,int R) { 87 if(ql <= L && R <= qr) return sumv[o]%P; 88 int ret = 0; 89 pushdown(o,L,R); 90 if(ql <= M) (ret += query(ls,L,M))%=P; 91 if(qr > M) (ret += query(rs,M+1,R))%=P; 92 return ret%P; 93 } 94 95 96 int LCA(int x,int y) { 97 int ret = 0; 98 while(tx != ty) { 99 if(deep[tx] >= deep[ty]) { 100 //x 走到 top[x](编号小) 的 爸爸 ,top[x] 的爸爸是轻链 101 ql = ID[tx], qr = ID[x];//下闭上开 102 (ret += query(1,1,n))%=P; 103 x = fa[tx]; 104 } 105 else { 106 ql = ID[ty], qr = ID[y]; 107 (ret += query(1,1,n))%=P; 108 y = fa[ty]; 109 } 110 } 111 112 if(x == y) { 113 ql = ID[x],qr = ql; 114 (ret += query(1,1,n))%=P; 115 return ret; 116 } 117 if(deep[x] > deep[y]) swap(x,y); 118 ql = ID[x], qr = ID[y]; 119 (ret += query(1,1,n))%=P; 120 return ret; 121 } 122 123 void LCA_add(int x,int y,int k) { 124 qa = k%P; 125 while(tx != ty) { 126 if(deep[tx] >= deep[ty]) { 127 //x 走到 top[x](编号小) 的 爸爸 ,top[x] 的爸爸是轻链 128 ql = ID[tx], qr = ID[x];//下闭上开 129 update(1,1,n); 130 x = fa[tx]; 131 } 132 else { 133 ql = ID[ty], qr = ID[y]; 134 update(1,1,n); 135 y = fa[ty]; 136 } 137 } 138 139 if(x == y) { 140 ql = ID[x],qr = ql; 141 update(1,1,n); 142 return; 143 } 144 if(deep[x] > deep[y]) swap(x,y); 145 ql = ID[x], qr = ID[y]; 146 update(1,1,n); 147 } 148 149 int main() { 150 scanf("%d %d %d %d",&n, &m, &root, &P); 151 for(int i = 1;i <= n;i++) scanf("%d",A+i); 152 for(int i = 1,x,y;i < n;i++) { 153 scanf("%d%d",&x,&y); 154 addedge(x,y); 155 addedge(y,x); 156 } 157 158 dfs1(root,1); 159 dfs2(root); 160 build(1,1,n); 161 162 for(int i = 1,x,l,r,z;i <= m;i++) { 163 scanf("%d",&x); 164 if(x == 1) { 165 scanf("%d%d%d",&l,&r,&z); 166 LCA_add(l,r,z); 167 } else if(x == 2) { 168 scanf("%d%d",&l,&r); 169 printf("%d ",LCA(l,r)); 170 } else if(x == 3) { 171 scanf("%d%d",&l,&z); 172 ql = ID[l],qr = ql+num[l]-1,qa=z; 173 update(1,1,n); 174 } else { 175 scanf("%d",&z); 176 ql = ID[z],qr = ql + num[z]-1; 177 printf("%d ",query(1,1,n)); 178 } 179 } 180 return 0; 181 }
以上是关于树链剖分模板的主要内容,如果未能解决你的问题,请参考以下文章