前言:

之前没学,多校中遇到了很多树上路径问题,速度来补补(板子)

前置技能:dfs序,lca,此处没用上树上差分,用线段树来维护dfs序

拿洛谷例题来说明一下树剖解决的问题:

https://www.luogu.com.cn/problem/P3384

最基础解决的问题就是树上路径的问题:求两个u,v,多次修改查询,u到v的路径和

首先我们明确,两点间的最短路径一定是经过lca的一条路径,也就是我们实际上就需要找

lca到u的链和lca到v的链

把一棵树分成多条重链和轻链

概念:

  • 重儿子:对于每一个非叶子节点,它的儿子中 儿子数量最多的那一个儿子 为该节点的重儿子
  • 轻儿子:对于每一个非叶子节点,它的儿子中 非重儿子 的剩下所有儿子即为轻儿子
  • 叶子节点没有重儿子也没有轻儿子(因为它没有儿子。。)
  • 重边:连接任意两个重儿子的边叫做重边
  • 轻边:剩下的即为轻边
  • 重链:相邻重边连起来的 连接一条重儿子 的链叫重链
  • 对于叶子节点,若其为轻儿子,则有一条以自己为起点的长度为1的链
  • 每一条重链以轻儿子为起点

我们先用两次搜索将重链和轻链划分:

void dfs1(int u,int f)
{
    dep[u]=dep[f]+1;//深度
    fa[u]=f;//记录父亲
    siz[u]=1;//子结点大小
    int maxson=-1;
    for(int i=head[u];i;i=e[i].next)
    {
        int v=e[i].v;
        if(v!=f)
        {
            dfs1(v,u);
            siz[u]+=siz[v];
            if(siz[v]>maxson)
            son[u]=v,maxson=siz[v];//更新
        }
    }
}
void dfs2(int u,int t)
{
    dfn[u]=++idx;//dfs序
    top[u]=t;//重链头
    w[idx]=dis[u];//dfs序上的点权值
    if(!son[u])
    return;
    dfs2(son[u],t);
    for(int i=head[u];i;i=e[i].next)
    {
        int v=e[i].v;
        if(v!=fa[u]&&v!=son[u])
        dfs2(v,v);
    }
}

 利用dfs序,一条链上的序号是连续的,也就是一段连续区间可以表示一个链,记录就行了,变成了线段树操作

洛谷板子完整代码:

  1 #include <iostream>
  2 #include <algorithm>
  3 #include <string>
  4 #include <vector>
  5 #include <stack>
  6 #include <cstring>
  7 #include <cmath>
  8 #include <cstdio>
  9 #include <unordered_map>
 10 #include <queue>
 11 #include <map>
 12 #include <sstream>
 13 #include <set>
 14 #include <cstdlib>
 15 #include <ctime>
 16 #include <unordered_set>
 17 #include <bitset>
 18 #include <chrono>
 19 using namespace std;
 20 typedef unsigned long long ull;
 21 typedef long long ll;
 22 //#pragma GCC optimize(3, "Ofast", "inline")
 23 #define MAX_INF 0x3f3f3f3f
 24 template <class T, class C>
 25 void print(C name, T a)
 26 {
 27     cout << name << ": " << a << endl;
 28 }
 29 template <class T>
 30 T gcd(T a, T b)
 31 {
 32     return b ? gcd(b, a % b) : a;
 33 }
 34 template <class T>
 35 T lcm(T a, T b)
 36 {
 37     return a * b / gcd(a, b);
 38 }
 39 ll pow(ll a, ll b, ll p)
 40 {
 41     ll ans = 1;
 42     a %= p;
 43     while (b)
 44     {
 45         if (b & 1)
 46             ans = ans * a % p;
 47         a = a * a % p;
 48         b >>= 1;
 49     }
 50     return ans;
 51 }
 52 template <typename _Tp>
 53 void read(_Tp &x)
 54 {
 55     char ch;
 56     bool flag = 0;
 57     x = 0;
 58     while (ch = getchar(), !isdigit(ch))
 59         if (ch == '-')
 60             flag = 1;
 61     while (isdigit(ch))
 62         x = x * 10 + ch - '0', ch = getchar();
 63     if (flag)
 64         x = -x;
 65 }
 66 template <class T>
 67 void print(T x)
 68 {
 69     if (x < 0)
 70     {
 71         x = -x;
 72         putchar('-');
 73     }
 74     if (x > 9)
 75         print(x / 10);
 76     putchar(x % 10 + '0');
 77 }
 78 ll mod = 998244353;
 79 const ll inf = 1e18;
 80 #define fir(i, a, b) for (int i = a; i <= b; i++)
 81 const int maxn = 1e5 + 20, N = 1e5+20, M = 3000 + 10;
 82 struct node
 83 {
 84     int v;
 85     int next;
 86 };
 87 int dep[maxn],fa[maxn],son[maxn],siz[maxn],head[maxn];
 88 ll dis[maxn],w[maxn];
 89 int dfn[maxn],idx=0,top[maxn];
 90 node e[maxn<<1];
 91 int tot=0;
 92 void add(int x,int y)
 93 {
 94     e[++tot] = {y, head[x]}, head[x] = tot;
 95 }
 96 ll add(ll x, ll t,ll mod) {    
 97 x %= mod;t %= mod;return (x + t) % mod;
 98 }
 99 void dfs1(int u,int f)
100 {
101     dep[u]=dep[f]+1;
102     fa[u]=f;
103     siz[u]=1;
104     int maxson=-1;
105     for(int i=head[u];i;i=e[i].next)
106     {
107         int v=e[i].v;
108         if(v!=f)
109         {
110             dfs1(v,u);
111             siz[u]+=siz[v];
112             if(siz[v]>maxson)
113             son[u]=v,maxson=siz[v];
114         }
115     }
116 }
117 void dfs2(int u,int t)
118 {
119     dfn[u]=++idx;
120     top[u]=t;
121     w[idx]=dis[u];
122     if(!son[u])
123     return;
124     dfs2(son[u],t);
125     for(int i=head[u];i;i=e[i].next)
126     {
127         int v=e[i].v;
128         if(v!=fa[u]&&v!=son[u])
129         dfs2(v,v);
130     }
131 }
132 #define left (i<<1)
133 #define right (i<<1|1)
134 struct Segnode
135 {
136     int l;
137     int r;
138     ll sum;
139     ll add;
140 };
141 Segnode sgt[maxn<<2];
142 inline void push_up(int i)
143 {
144     sgt[i].sum=(sgt[left].sum+sgt[right].sum)%mod;
145 }
146 void build(int l,int r,int i)
147 {
148     sgt[i].l=l;
149     sgt[i].r=r;
150     if(l==r)
151     {
152         sgt[i].sum=w[l];
153         return;
154     }
155     int mid=(l+r)>>1;
156     build(l,mid,left);
157     build(mid+1,r,right);
158     push_up(i);
159 }
160 inline void push_down(int i)
161 {
162     if(sgt[i].add)
163     {
164         sgt[left].sum=add(sgt[left].sum,sgt[i].add*(sgt[left].r-sgt[left].l+1),mod);
165         sgt[left].add+=sgt[i].add;
166         sgt[right].sum=add(sgt[right].sum,sgt[i].add*(sgt[right].r-sgt[right].l+1),mod);
167         sgt[right].add+=sgt[i].add;
168         sgt[i].add=0;
169     }
170 }
171 ll query(int l,int r,int i)
172 {
173     if(l<=sgt[i].l&&sgt[i].r<=r)
174     {
175         return sgt[i].sum;
176     }
177     push_down(i);
178     int mid=(sgt[i].l+sgt[i].r)>>1;
179     ll ans=0;
180     if(l<=mid)
181     ans=add(ans,query(l,r,left),mod);
182     if(r>mid)
183     ans=add(ans,query(l,r,right),mod);
184     push_up(i);
185     return ans;
186 }
187 void change(int l,int r,int i,ll x)
188 {
189     if(l<=sgt[i].l&&sgt[i].r<=r)
190     {
191         sgt[i].sum=add(sgt[i].sum,(sgt[i].r-sgt[i].l+1)*x,mod);
192         sgt[i].add=add(sgt[i].add,x,mod);
193         return;
194     }
195     push_down(i);
196     int mid=(sgt[i].l+sgt[i].r)>>1;
197     if(l<=mid)
198     change(l,r,left,x);
199     if(r>mid)
200     change(l,r,right,x);
201     push_up(i);
202 }
203 void mofidy(int x,int y,ll z)
204 {
205     while(top[x]!=top[y])
206     {
207         if(dep[top[x]]<dep[top[y]])swap(x,y);
208         change(dfn[top[x]],dfn[x],1,z);
209         x=fa[top[x]];
210     }
211     if(dep[x]>dep[y])
212     swap(x,y);
213     change(dfn[x],dfn[y],1,z);
214 }
215 ll qrange(int x,int y)
216 {
217     ll ans=0;
218     while(top[x]!=top[y])
219     {
220         if(dep[top[x]]<dep[top[y]])swap(x,y);
221         ans=add(ans,query(dfn[top[x]],dfn[x],1),mod);
222         x=fa[top[x]];
223     }
224     if(dep[x]>dep[y])
225     swap(x,y);
226     ans=add(ans,query(dfn[x],dfn[y],1),mod);
227     return ans;
228 }
229 int main()
230 {
231     int n,Q,root;
232     cin>>n>>Q>>root>>mod;
233     fir(i,1,n)
234     scanf("%lld",&dis[i]);
235     fir(i,1,n-1)
236     {
237         int x,y;
238         scanf("%d%d",&x,&y);
239         add(x,y),add(y,x);
240     }
241     dfs1(root,0);
242     dfs2(root,0);
243     build(1,idx,1);
244     while(Q--)
245     {
246         int ch;
247         scanf("%d",&ch);
248         int x,y;ll z;
249         if(ch==1)
250         {
251             scanf("%d%d%lld",&x,&y,&z);
252             mofidy(x,y,z);
253         }
254         else if(ch==2)
255         {
256             scanf("%d%d",&x,&y);
257             ll ans=qrange(x,y);
258             printf("%lld\n",ans);
259         }
260         else if(ch==3)
261         {
262             scanf("%d%lld",&x,&z);
263             change(dfn[x],dfn[x]+siz[x]-1,1,z);
264         }
265         else 
266         {
267             scanf("%d",&x);
268             printf("%lld\n",query(dfn[x],dfn[x]+siz[x]-1,1));
269         }
270     }
271 }

 

posted on 2020-08-18 21:51    阅读(125)  评论(0)    收藏  举报