有关树链剖分的内容,其中有一篇文章我十分推荐

http://www.cnblogs.com/chinhhh/p/7965433.html

SRE实战 互联网时代守护先锋,助力企业售后服务体系运筹帷幄!一键直达领取阿里云限量特价优惠。

 

这里面讲的树链剖分内容也还算是比较详细了

 

接下来是我自己对树链剖分的一系列理解

 

首先是,树上的操作,单一操作比如说:x—y的路径上全部加和,这个时候我们可以利用树上差分的思想来做,这个时候再加上LCA可以达到修改O(1),查询O(N)

但是如果是多次修改多次查询,极端的情况下复杂度能够到达O(N^2)(原因就是一次修改一次查询,每次都要用O(N)来查询)

接下来我们就引入了树链剖分

其实就是进行两次dfs,第一次dfs记录树上信息,第二次dfs将树上的链转化成一个又一个连续的区间,用线段树或者树状数组这样的数据结构进行维护

树链剖分查询查询修改的时间复杂度是NlogN(因为通过长链的拼接,来拆分成至少longer/2的长度)

 

基本需要维护的树上信息就是deep深度,fa父亲,size子树大小,son重儿子节点

然后转化成区间的操作,为了让链条连续,并且尽量让长的尽量长,这个时候就是将重儿子的所在链优先处理,然后再处理其他的儿子

这个时候需要维护的信息就是转化成区间上该点所在区间上的ID,以及该id所对应的点,该点在原数组的数据,链条端点用于快速跳转,

 

这个时候操作X点和Y点的路径上的数据的时候,一直往上找TOP,如果他们的TOP不相等,说明还未在一条链上,这个时候只需要在他们的连续的链上直接用数据结构进行操作,一直到他们的top节点相等,这个时候他们必定在在一条链上

 

  1 #include <bits/stdc++.h>
  2 
  3 typedef long long ll;
  4 
  5 const int MAXN=100010, MAXM=1000010;
  6 
  7 int N, M, R, MOD;
  8 
  9 int ver[MAXM],next[MAXM],/* edge[MAXM], */head[MAXN],tot;
 10 int deep[MAXN],fa[MAXN],size[MAXN],son[MAXN];
 11 int id[MAXN],rk[MAXN];
 12 int top[MAXN];
 13 int pos;
 14 
 15 struct SegmentTree {
 16     int l, r;
 17     int dat;
 18     int lazy;
 19 } Tree[MAXN * 4];
 20 int num[MAXN],NUM[MAXN];
 21 
 22 void build(int p, int l, int r) {
 23     Tree[p].l = l;
 24     Tree[p].r = r;
 25     if (l == r) {
 26         Tree[p].dat = num[l];
 27         return;
 28     }
 29     int mid = (l + r) >> 1;
 30     build(p * 2, l, mid);
 31     build(p * 2 + 1, mid + 1, r);
 32     Tree[p].dat = (Tree[p * 2].dat + Tree[p * 2 + 1].dat)%MOD;
 33 }
 34 
 35 void spread(int p) {
 36     if (Tree[p].lazy) {
 37         Tree[p * 2].dat += (Tree[p].lazy * (Tree[p * 2].r - Tree[p * 2].l + 1));
 38         Tree[p*2].dat%=MOD;
 39         Tree[p * 2 + 1].dat += (Tree[p].lazy * (Tree[p * 2 + 1].r - Tree[p * 2 + 1].l + 1));
 40         Tree[p*2+1].dat%=MOD;
 41         Tree[p * 2].lazy += Tree[p].lazy;
 42         Tree[p * 2 + 1].lazy += Tree[p].lazy;
 43         Tree[p].lazy = 0;
 44     }
 45 }
 46 
 47 void change(int p, int l, int r, int d) {
 48     if (l <= Tree[p].l && Tree[p].r <= r) {
 49         Tree[p].dat += (long long)d * (Tree[p].r - Tree[p].l + 1);
 50         Tree[p].dat%=MOD;
 51         Tree[p].lazy += d;
 52         return;
 53     }
 54     spread(p);
 55     int mid = (Tree[p].l + Tree[p].r) >> 1;
 56     if (l <= mid) change(p * 2, l, r, d);
 57     if (mid < r) change(p * 2 + 1, l, r, d);
 58     Tree[p].dat = Tree[p * 2].dat + Tree[p * 2 + 1].dat;
 59     Tree[p].dat%=MOD;
 60 }
 61 
 62 long long ask(int p, int l, int r) {
 63     if (l <= Tree[p].l && Tree[p].r <= r) return Tree[p].dat;
 64     spread(p);
 65     int mid = (Tree[p].l + Tree[p].r) >> 1;
 66     long long val = 0;
 67     if (l <= mid) val += ask(p * 2, l, r),val%=MOD;
 68     if (mid < r) val += ask(p * 2 + 1, l, r),val%=MOD;
 69     return val;
 70 }
 71 
 72 void addedge(int u,int v){
 73     ver[++tot]=v;
 74     next[tot]=head[u];
 75     head[u]=tot;
 76 }
 77 
 78 void dfs1(int u,int par,int d){
 79     deep[u]=d;
 80     fa[u]=par;
 81     size[u]=1;
 82     for(int i=head[u];i;i=next[i])
 83     {
 84         int v=ver[i];
 85         if(v!=par)
 86         {
 87             dfs1(v,u,d+1);
 88             size[u]+=size[v];
 89             if(size[v]>size[son[u]])
 90                 son[u]=v;
 91         }
 92     }
 93 }
 94 
 95 void dfs2(int u,int sp){
 96     top[u]=sp;
 97     id[u]=++pos;
 98     num[pos]=NUM[u];
 99     rk[pos]=u;
100     if(son[u]==0) return;
101     dfs2(son[u],sp);
102     for(int i=head[u];i;i=next[i])
103     {
104         int v=ver[i];
105         if(v!=son[u] && v!=fa[u])
106             dfs2(v,v);
107     }
108 }
109 
110 ll queryRange(int l,int r){
111     ll ans=0;
112     while(top[l]!=top[r])
113     {
114         if(deep[top[l]]<deep[top[r]])
115             std::swap(l,r);
116         ans+=ask(1,id[top[l]],id[l]);
117         ans%=MOD;
118         l=fa[top[l]];
119     }
120     if(deep[l]>deep[r]) std::swap(l,r);
121     ans+=ask(1,id[l],id[r]);
122     ans%=MOD;
123 
124     return ans;
125 }
126 
127 ll querySon(int p){
128     return ask(1,id[p],id[p]+size[p]-1);
129 }
130 
131 void changeRange(int l,int r,int d){
132     while(top[l]!=top[r])
133     {
134         if(deep[top[l]]<deep[top[r]])
135             std::swap(l,r);
136         change(1,id[top[l]],id[l],d);
137         l=fa[top[l]];
138     }
139     if(deep[l]>deep[r])
140         std::swap(l,r);
141     change(1,id[l],id[r],d);
142 }
143 
144 void changeSon(int p,int d){
145     change(1,id[p],id[p]+size[p]-1,d);
146 }
147 
148 int main(){
149     std::cin>>N>>M>>R>>MOD;
150     for(int i=1;i <= N;i++)
151         scanf("%d",&NUM[i]);
152     for(int i=1;i < N;i++)
153     {
154         int x,y;
155         scanf("%d%d",&x,&y);
156         addedge(x,y);
157         addedge(y,x);
158     }
159     dfs1(R,0,1);
160     dfs2(R,R);
161     build(1,1,N);
162     int x,y,z;
163     ll ans=0;
164     for(int i=1;i <= M;i++)
165     {
166         int opera;
167         scanf("%d",&opera);
168         if(opera == 1)
169         {
170             scanf("%d%d%d",&x,&y,&z);
171             changeRange(x,y,z);
172         }
173         if(opera==2)
174         {
175             scanf("%d%d",&x,&y);
176             ans=queryRange(x,y);
177             printf("%lld\n",ans);
178         }
179         if(opera==3)
180         {
181             scanf("%d%d",&x,&y);
182             /* printf("%d %d\n",id[x],id[x]+size[x]-1); */
183             changeSon(x,y);
184         }
185         if(opera==4)
186         {
187             scanf("%d",&x);
188             ans=querySon(x);
189             printf("%lld\n",ans);
190         }
191     }
192     return 0;
193 }

 

扫码关注我们
微信号:SRE实战
拒绝背锅 运筹帷幄