• 树链剖分 点权下放边权


    Grass Planting G

    大意:

    就那么些操作,没有大意

    思路:
    这里就简单讲一下如何实现

    首先,对于一条边,它有两个顶点,那么肯定是让深度较浅的点,也就是父节点的点权来作为这条边的边权。然后最后我们要查边权的时候,只要查它对应的子节点就可以了

    那么我们为了实现该操作,在原本的板子上,有三点要进行改变:

    1.dfs时更新点权,也就是让边权赋给子节点

    1. for(int i=head[id];i!=-1;i=edge[i].next)
    2. {
    3. ll y=edge[i].t;
    4. if(y==p) continue;
    5. a[y]=edge[i].l; //如果初始边权不为0,点权下放边权时要执行这一句操作
    6. init_dfs(y,id,depth+1);
    7. siz[id]+=siz[y];
    8. if(siz[y]>son_val)
    9. {
    10. son_val=siz[y];
    11. son[id]=y;
    12. }
    13. }

    2.树上路径更新的时候,你稍微手玩一下就会发现两个节点的lca是不应该被更新的,所以在最后一步更新的时候,我们的代码要有所改变

    1. ll tree_add(ll x,ll y,ll val)
    2. {
    3. while(top[x]!=top[y])
    4. {
    5. if(dep[top[x]]swap(x,y);
    6. add(1,idx[top[x]],idx[x],val);
    7. x=fa[top[x]];
    8. }
    9. if(dep[x]>dep[y]) swap(x,y);
    10. add(1,idx[x]+1,idx[y],val);//lca不查询,所以x要+1
    11. }

    当然你也可以这么写

    1. ll tree_add(ll x,ll y,ll val)
    2. {
    3. while(top[x]!=top[y])
    4. {
    5. if(dep[top[x]]swap(x,y);
    6. add(1,idx[top[x]],idx[x],val);
    7. x=fa[top[x]];
    8. }
    9. if(dep[x]>dep[y]) swap(x,y);
    10. add(1,idx[x],idx[y],val);
    11. add(1,idx[x],idx[x],-val);
    12. }

    其实就是把lca的更新的结果给改回去

    3.查询树上路径权值和时(如果有这个操作),同理两点的lca的点权不应该被算进去,因为它对应的边不属于这两点的路径上。

    1. ll tree_sum(ll x,ll y)
    2. {
    3. ll ans=0;
    4. while(top[x]!=top[y])
    5. {
    6. if(dep[top[x]]swap(x,y);
    7. ans+=sum(1,idx[top[x]],idx[x]);
    8. x=fa[top[x]];
    9. }
    10. if(dep[x]>dep[y]) swap(x,y);
    11. ans+=sum(1,idx[x]+1,idx[y]);//点权下放边权操作核心代码,lca不查询,所以x要+1
    12. return ans;
    13. }

    同理,你也可以这么写,意思我就不解释了

    1. ll tree_sum(ll x,ll y)
    2. {
    3. ll ans=0;
    4. while(top[x]!=top[y])
    5. {
    6. if(dep[top[x]]swap(x,y);
    7. ans+=sum(1,idx[top[x]],idx[x]);
    8. x=fa[top[x]];
    9. }
    10. if(dep[x]>dep[y]) swap(x,y);
    11. ans+=sum(1,idx[x],idx[y]);
    12. ans-=sum(1,idx[x],idx[x]);
    13. return ans;
    14. }

    会了这个操作之后这题你就毫无问题了

    不过按惯例还是贴一下code

    1. #include
    2. using namespace std;
    3. #define ll int
    4. #define endl '\n'
    5. const ll N=1e5+10;
    6. struct ty{
    7. ll t,l,next;
    8. }edge[N<<1];
    9. ll cn=0;
    10. ll n,k;
    11. char op;
    12. ll aa,b,c,rt;
    13. ll head[N];
    14. void add_edge(ll a,ll b,ll c)
    15. {
    16. edge[++cn].t=b;
    17. edge[cn].l=c;
    18. edge[cn].next=head[a];
    19. head[a]=cn;
    20. }
    21. struct tree
    22. {
    23. ll l,r;
    24. ll val;
    25. ll add;//lazy
    26. ll siz;
    27. }tr[N<<2];
    28. ll dep[N];//深度
    29. ll fa[N],son[N];
    30. ll siz[N];
    31. ll mas[N],a[N];//初始序列,处理后的序列
    32. ll cnt=0;//dfs序的时间戳
    33. ll top[N];//所在链的顶端
    34. ll idx[N];
    35. void init_dfs(ll id,ll p,ll depth)
    36. {
    37. dep[id]=depth;
    38. fa[id]=p;
    39. siz[id]=1;
    40. ll son_val=0;
    41. for(int i=head[id];i!=-1;i=edge[i].next)
    42. {
    43. ll y=edge[i].t;
    44. if(y==p) continue;
    45. //a[y]=edge[i].l; 如果初始边权不为0,点权下放边权时要执行这一句操作
    46. init_dfs(y,id,depth+1);
    47. siz[id]+=siz[y];
    48. if(siz[y]>son_val)
    49. {
    50. son_val=siz[y];
    51. son[id]=y;
    52. }
    53. }
    54. }
    55. void dfs2(ll id,ll p)
    56. {//更新链上的情况
    57. idx[id]=++cnt;
    58. a[cnt]=mas[id];
    59. top[id]=p;
    60. if(!son[id]) return;
    61. dfs2(son[id],p);
    62. for(int i=head[id];i!=-1;i=edge[i].next)
    63. {
    64. ll y=edge[i].t;
    65. //if(y==p||y==son[id]) continue;
    66. if(!idx[y]) dfs2(y,y);//新的链
    67. }
    68. }
    69. void push_up(ll p)
    70. {
    71. tr[p].val+=tr[p<<1].val+tr[p<<1|1].val;
    72. }
    73. void build(ll p,ll l,ll r)
    74. {
    75. tr[p].l=l;tr[p].r=r;tr[p].siz=r-l+1;
    76. if(l==r)
    77. {
    78. tr[p].val=a[l];
    79. return;
    80. }
    81. ll mid=l+r>>1;
    82. build(p<<1,l,mid);
    83. build(p<<1|1,mid+1,r);
    84. }
    85. void push_down(ll p)
    86. {
    87. if(tr[p].add==0) return;
    88. tr[p<<1].val+=tr[p<<1].siz*tr[p].add;
    89. tr[p<<1|1].val+=tr[p<<1|1].siz*tr[p].add;
    90. tr[p<<1].add+=tr[p].add;
    91. tr[p<<1|1].add+=tr[p].add;
    92. tr[p].add=0;
    93. }
    94. void add(ll p,ll l,ll r,ll val)
    95. {
    96. if(tr[p].l>=l&&tr[p].r<=r)
    97. {
    98. tr[p].val+=tr[p].siz*val;
    99. tr[p].add+=val;
    100. return;
    101. }
    102. push_down(p);
    103. ll mid=tr[p].l+tr[p].r>>1;
    104. if(l<=mid) add(p<<1,l,r,val);
    105. if(r>mid) add(p<<1|1,l,r,val);
    106. push_up(p);
    107. }
    108. ll sum(ll p,ll l,ll r)
    109. {
    110. ll ans=0;
    111. if(tr[p].l>=l&&tr[p].r<=r)
    112. {
    113. return tr[p].val;
    114. }
    115. push_down(p);
    116. ll mid=tr[p].l+tr[p].r>>1;
    117. if(l<=mid) ans+=sum(p<<1,l,r);
    118. if(r>mid) ans+=sum(p<<1|1,l,r);
    119. return ans;
    120. }
    121. ll tree_sum(ll x,ll y)
    122. {
    123. ll ans=0;
    124. while(top[x]!=top[y])
    125. {
    126. if(dep[top[x]]swap(x,y);
    127. ans+=sum(1,idx[top[x]],idx[x]);
    128. x=fa[top[x]];
    129. }
    130. if(dep[x]>dep[y]) swap(x,y);
    131. ans+=sum(1,idx[x]+1,idx[y]);//点权下放边权操作核心代码,lca不查询,所以y要+1
    132. return ans;
    133. }
    134. ll tree_add(ll x,ll y,ll val)
    135. {
    136. while(top[x]!=top[y])
    137. {
    138. if(dep[top[x]]swap(x,y);
    139. add(1,idx[top[x]],idx[x],val);
    140. x=fa[top[x]];
    141. }
    142. if(dep[x]>dep[y]) swap(x,y);
    143. add(1,idx[x]+1,idx[y],val);//同上一句注释
    144. }
    145. void trson_add(ll x,ll val)
    146. {
    147. add(1,idx[x],idx[x]+siz[x]-1,val);
    148. }
    149. ll trson_sum(ll x)
    150. {
    151. return sum(1,idx[x],idx[x]+siz[x]-1);
    152. }
    153. void solve()
    154. {
    155. cin>>n>>k;
    156. for(int i=1;i
    157. {
    158. cin>>aa>>b;
    159. add_edge(aa,b,0);
    160. add_edge(b,aa,0);
    161. }
    162. init_dfs(rt,0,1);
    163. dfs2(rt,rt);
    164. build(1,1,n);
    165. while(k--)
    166. {
    167. cin>>op>>aa>>b;
    168. if(op=='P')
    169. {
    170. tree_add(aa,b,1);
    171. }
    172. else cout<<tree_sum(aa,b)<
    173. }
    174. }
    175. int main()
    176. {ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
    177. memset(head,-1,sizeof head);
    178. rt=1;
    179. solve();
    180. return 0;
    181. }

  • 相关阅读:
    基于SpringBoot的服装生产管理系统的设计与实现
    Coursera耶鲁大学金融课程:Financial Markets 笔记Week 02
    Java 终极学习路线 - 共计 9 大模块 /6 大框架 /13 个中间件
    【ATT&CK】ATT&CK视角下的水坑钓鱼攻防战法
    图像文本跨模态细粒度语义对齐-置信度校正机制 AAAI2022
    第83步 时间序列建模实战:Catboost回归建模
    分布式消息队列RocketMQ概念详解
    java之《浅入了解异常》适合预习,复习
    java-php-net-python-基于ssh的酒店客房在线预定计算机毕业设计程序
    第11章_数据处理之增删改
  • 原文地址:https://blog.csdn.net/sophilex/article/details/126432341