博客园 首页 私信博主 显示目录 隐藏目录 管理 动画

树链剖分

推荐博客:

https://www.cnblogs.com/ivanovcraft/p/9019090.html

这讲的很好,主要是用来处理树上路径问题的高效算法

首先明确概念:

重儿子:父亲节点的所有儿子中子树结点数目最多(size最大)的结点;

轻儿子:父亲节点中除了重儿子以外的儿子;

重边:父亲结点和重儿子连成的边;

轻边:父亲节点和轻儿子连成的边;

重链:由多条重边连接而成的路径;

轻链:由多条轻边连接而成的路径;

名称 解释
f[u] 保存结点u的父亲节点
d[u] 保存结点u的深度值
size[u] 保存以u为根的子树节点个数
son[u] 保存重儿子
rk[u] 保存当前dfs标号在树中所对应的节点
top[u] 保存当前节点所在链的顶端节点
id[u] 保存树中每个节点剖分以后的新编号(DFS的执行顺序)

 

题目:洛谷 https://www.luogu.org/problem/P3384

ac代码:

  1 #include<bits/stdc++.h>
  2 const ll MAX=100000+5;
  3 ll p;
  4 vector<ll>q[maxn];
  5 ll f[maxn];
  6 ll d[maxn];
  7 ll siz[maxn];
  8 ll son[maxn];
  9 
 10 ll top[maxn];
 11 ll id[maxn];
 12 ll rk[maxn];
 13 
 14 ll a[maxn];
 15 
 16 struct Tree
 17 {
 18     ll l,r,sum;
 19 } tree[maxn<<2];
 20 ll dfs(ll a,ll fa)
 21 {
 22     f[a]=fa;
 23     d[a]=d[fa]+1;
 24     siz[a]=1;
 25     for(ll i=0; i<q[a].size(); i++)
 26     {
 27         ll z=q[a][i];
 28         if(z!=fa)
 29         {
 30             dfs(z,a);
 31             siz[a]+=siz[z];
 32             if(!son[a]||siz[z]>siz[son[a]])
 33                 son[a]=z;
 34         }
 35     }
 36     return 0;
 37 }
 38 ll lz[maxn];
 39 void build(ll x,ll l,ll r)
 40 {
 41     tree[x].l=l;
 42     tree[x].r=r;
 43     if(l==r)
 44         tree[x].sum=a[rk[l]];
 45     if(l==r)return ;
 46     ll mid=(l+r)>>1;
 47     build(x<<1,l,mid);
 48     build(x<<1|1,mid+1,r);
 49     tree[x].sum=(tree[x<<1].sum+tree[x<<1|1].sum);
 50 }
 51 void pushup(ll x)
 52 {
 53     ll LL,rr;
 54     LL=tree[x].l;
 55     rr=tree[x].r;
 56     ll k=lz[x];
 57     lz[x<<1]+=k;
 58     lz[x<<1|1]+=k;
 59     ll mid=(LL+rr)>>1;
 60     tree[x<<1].sum+=(mid-LL+1)*lz[x];
 61     tree[x<<1].sum%=p;
 62     tree[x<<1|1].sum+=(rr-mid)*lz[x];
 63     tree[x<<1|1].sum%=p;
 64     lz[x]=0;
 65 
 66 }
 67 
 68 void add(ll x,ll l,ll r,ll k)
 69 {
 70     ll LL,rr;
 71     LL=tree[x].l;
 72     rr=tree[x].r;
 73     if(l<=LL&&rr<=r)
 74     {
 75         tree[x].sum=(tree[x].sum+(rr-LL+1)*k)%p;
 76         lz[x]+=k;
 77         return ;
 78     }
 79     if(lz[x]) pushup(x);
 80     ll mid=(LL+rr)>>1;
 81     if(mid>=l) add(x<<1,l,r,k);
 82     if(mid<r)add(x<<1|1,l,r,k);
 83     tree[x].sum=(tree[x<<1].sum+tree[x<<1|1].sum)%p;
 84 }
 85 ll pri(ll x,ll l,ll r)
 86 {
 87     ll sum=0;
 88     ll LL,rr;
 89     LL=tree[x].l;
 90     rr=tree[x].r;
 91     if(l<=LL&&rr<=r)
 92     {
 93         return tree[x].sum;
 94     }
 95     if(lz[x]) pushup(x);
 96     ll mid=(LL+rr)>>1;
 97     if(mid>=l) sum+=pri(x<<1,l,r);
 98     sum%=p;
 99     if(mid<r)sum+=pri(x<<1|1,l,r);
100     return sum%p;
101 }
102 ll sum;
103 void dfs1(ll a,ll b)
104 {
105     top[a]=b;
106     id[a]=++sum;
107     rk[sum]=a;
108     if(!son[a])
109         return ;
110     dfs1(son[a],b);
111     for(ll i=0; i<q[a].size(); i++)
112     {
113         ll z=q[a][i];
114         if(z!=f[a]&&z!=son[a])
115             dfs1(z,z);
116     }
117 }
118 void Q1(ll x,ll y,ll z)
119 {
120     while(top[x]!=top[y])
121     {
122         if(d[top[x]]<d[top[y]])swap(x,y);
123         add(1,id[top[x]],id[x],z);
124         x=f[top[x]];
125     }
126     if(d[x]>d[y])swap(x,y);
127     add(1,id[x],id[y],z);
128 }
129 ll Q2(ll x,ll y)
130 {
131     ll sum=0;
132     while(top[x]!=top[y])
133     {
134         if(d[top[x]]<d[top[y]])swap(x,y);
135         sum=(sum+pri(1,id[top[x]],id[x]))%p;
136         x=f[top[x]];
137     }
138     if(d[x]>d[y])swap(x,y);
139     sum=(sum+pri(1,id[x],id[y]))%p;
140     return (sum+p)%p;
141 }
142 void Q3(ll x,ll z)
143 {
144     add(1,id[x],id[x]+siz[x]-1,z);
145 }
146 int main()
147 {
148     // ios::sync_with_stdio(false);
149     ll  n,m,r;
150     scanf("%lld%lld%lld%lld",&n,&m,&r,&p);
151     for(ll i=1; i<=n; i++)
152         scanf("%lld",&a[i]);
153     for(ll i=1; i<n; i++)
154     {
155         ll x,y;
156         scanf("%lld%lld",&x,&y);
157         q[x].pb(y);
158         q[y].pb(x);
159     }
160     dfs(r,0);
161     dfs1(r,r);
162     build(1,1,n);
163     while(m--)
164     {
165         ll a;
166         cin>>a;
167         if(a==1)
168         {
169             ll x,y,z;
170             scanf("%lld%lld%lld",&x,&y,&z);z%=p;
171             Q1(x,y,z);
172         }
173         else if(a==2)
174         {
175             ll x,y;
176             cin>>x>>y;
177             cout<<Q2(x,y)<<endl;
178         }
179         else if(a==3)
180         {
181             ll x,z;z%=p;
182             cin>>x>>z;
183             Q3(x,z);
184         }
185         else
186         {
187             ll x;
188             cin>>x;
189             cout<<(pri(1,id[x],id[x]+siz[x]-1)+p)%p<<endl;
190         }
191     }
192 }
View Code

 

posted @ 2019-07-30 21:29  GUET_uzi  阅读(121)  评论(0编辑  收藏  举报

- 创建于 2018年9月1日

这是一位ACM爱好者&数学爱好者的个人站,内容主要是算法&数据结构&数学研究的技术文章,大部分来自学习,部分来源于网络,希望对大家有所帮助。