「模板」 树链剖分 HLD

<题目链接>


不懂OOP的OIer乱用OOP出人命了。

谨此纪念人生第一次类套类。

以及第一次OI相关代码打过200行。

#include <algorithm>
#include <cstdio>
#include <cstring>
using std::swap;
const int MAXN=100010,MAXM=200010;
int n,m,rt,P;
class HLD
{
public:
HLD(void)
{
num=cnt=0;
memset(vis,0,sizeof vis);
memset(head,0,sizeof head);
memset(p,0,sizeof p);
}
void Init(void)
{
for(int i=1;i<=n;++i)
scanf("%d",&p[i].v);
for(int i=1,x,y;i<n;++i)
{
scanf("%d %d",&x,&y);
AddEdges(x,y);
}
DFS1(rt,1),DFS2(rt,rt),T.Build(this,1,1,n);
}
void AddPath(int x,int y,int v)
{
int a,b;
while((a=p[x].top)^(b=p[y].top))
p[a].d>p[b].d ? (T.Add(1,p[a].DFN,p[x].DFN,v),x=p[a].ft) : (T.Add(1,p[b].DFN,p[y].DFN,v),y=p[b].ft);
if(p[x].d>p[y].d)
swap(x,y);
T.Add(1,p[x].DFN,p[y].DFN,v);
}
int SumPath(int x,int y)
{
int a,b,ans=0;
while((a=p[x].top)^(b=p[y].top))
p[a].d>p[b].d ? (ans+=T.Sum(1,p[a].DFN,p[x].DFN),x=p[a].ft) : (ans+=T.Sum(1,p[b].DFN,p[y].DFN),y=p[b].ft);
if(p[x].d>p[y].d)
swap(x,y);
return (ans+T.Sum(1,p[x].DFN,p[y].DFN))%P;
}
void AddSubtree(int x,int v)
{
T.Add(1,p[x].DFN,p[x].DFN+p[x].size-1,v);
}
int SumSubtree(int x)
{
return T.Sum(1,p[x].DFN,p[x].DFN+p[x].size-1);
}
private:
bool vis[MAXN];
int cnt,num,head[MAXN],rank[MAXN];
struct node
{
int v,d,ft,son,size,top,DFN;
}p[MAXN];
struct edge
{
int nxt,to;
edge(int _nxt=0,int _to=0)
{
nxt=_nxt,to=_to;
}
}e[MAXM];
class SegmentTree
{
public:
void Build(HLD *qwq,int i,int l,int r)
{
s[i]=node(l,r,0);
if(l==r)
{
s[i].v=qwq->p[qwq->rank[l]].v;
return;
}
int j=i<<1,mid=l+r>>1;
Build(qwq,j,l,mid),Build(qwq,j|1,mid+1,r);
PushUp(i);
}
void Add(int i,int l,int r,int v)
{
if(l==s[i].l && r==s[i].r)
{
Update(i,v);
return;
}
if(s[i].l^s[i].r && s[i].lazy)
PushDown(i);
int j=i<<1,mid=s[i].l+s[i].r>>1;
if(r<=mid)
Add(j,l,r,v);
else if(l>mid)
Add(j|1,l,r,v);
else
Add(j,l,mid,v),Add(j|1,mid+1,r,v);
PushUp(i);
}
int Sum(int i,int l,int r)
{
if(l==s[i].l && r==s[i].r)
return s[i].v;
if(s[i].l^s[i].r && s[i].lazy)
PushDown(i);
int j=i<<1,mid=s[i].l+s[i].r>>1;
if(r<=mid)
return Sum(j,l,r);
else if(l>mid)
return Sum(j|1,l,r);
else
return (Sum(j,l,mid)+Sum(j|1,mid+1,r))%P;
}
private:
struct node
{
int l,r,v,lazy;
node(int _l=0,int _r=0,int _lazy=0)
{
l=_l,r=_r,lazy=_lazy;
}
}s[MAXN<<2];
void Update(int i,int v)
{
s[i].v=(s[i].v+v*(s[i].r-s[i].l+1))%P;
s[i].lazy=(s[i].lazy+v)%P;
}
void PushUp(int i)
{
int j=i<<1;
s[i].v=(s[j].v+s[j|1].v)%P;
}
void PushDown(int i)
{
int j=i<<1;
Update(j,s[i].lazy),Update(j|1,s[i].lazy);
s[i].lazy=0;
}
}T;
void AddEdge(int u,int v)
{
e[++cnt]=edge(head[u],v);
head[u]=cnt;
}
void AddEdges(int u,int v)
{
AddEdge(u,v),AddEdge(v,u);
}
void DFS1(int u,int k)
{
p[u].d=k,p[u].size=1;
for(int i=head[u],v;i;i=e[i].nxt)
if(!p[v=e[i].to].size)
{
DFS1(v,k+1);
p[v].ft=u,p[u].size+=p[v].size;
if(p[v].size>p[p[u].son].size)
p[u].son=v;
}
}
void DFS2(int u,int top)
{
p[u].top=top,vis[u]=1;
p[u].DFN=++num,rank[num]=u;
if(p[u].son)
DFS2(p[u].son,top);
for(int i=head[u],v;i;i=e[i].nxt)
if(!vis[v=e[i].to])
DFS2(v,v);
}
}HLT;
int main(int argc,char *argv[])
{
scanf("%d %d %d %d",&n,&m,&rt,&P);
HLT.Init();
for(int i=1,opt,x,y,z;i<=m;++i)
{
scanf("%d %d",&opt,&x);
switch(opt)
{
case 1:
scanf("%d %d",&y,&z);
HLT.AddPath(x,y,z);
break;
case 2:
scanf("%d",&y);
printf("%d\n",HLT.SumPath(x,y));
break;
case 3:
scanf("%d",&z);
HLT.AddSubtree(x,z);
break;
case 4:
printf("%d\n",HLT.SumSubtree(x));
break;
}
}
return 0;
}

谢谢阅读。

「模板」 树链剖分 HLD的更多相关文章

  1. P3384 【模板】树链剖分

    P3384 [模板]树链剖分 题目描述 如题,已知一棵包含N个结点的树(连通且无环),每个节点上包含一个数值,需要支持以下操作: 操作1: 格式: 1 x y z 表示将树从x到y结点最短路径上所有节 ...

  2. luogu3384 【模板】树链剖分

    P3384 [模板]树链剖分 题目描述 如题,已知一棵包含N个结点的树(连通且无环),每个节点上包含一个数值,需要支持以下操作: 操作1: 格式: 1 x y z 表示将树从x到y结点最短路径上所有节 ...

  3. 【算法学习】【洛谷】树链剖分 & P3384 【模板】树链剖分 P2146 软件包管理器

    刚学的好玩算法,AC2题,非常开心. 其实很早就有教过,以前以为很难就没有学,现在发现其实很简单也很有用. 更重要的是我很好调试,两题都是几乎一遍过的. 介绍树链剖分前,先确保已经学会以下基本技巧: ...

  4. 洛谷 P3384 【模板】树链剖分-树链剖分(点权)(路径节点更新、路径求和、子树节点更新、子树求和)模板-备注结合一下以前写的题目,懒得写很详细的注释

    P3384 [模板]树链剖分 题目描述 如题,已知一棵包含N个结点的树(连通且无环),每个节点上包含一个数值,需要支持以下操作: 操作1: 格式: 1 x y z 表示将树从x到y结点最短路径上所有节 ...

  5. 树链剖分 - Luogu 3384【模板】树链剖分

    [模板]树链剖分 题目描述 已知一棵包含N个结点的树(连通且无环),每个节点上包含一个数值,需要支持以下操作: 操作1: 格式: 1 x y z 表示将树从x到y结点最短路径上所有节点的值都加上z 操 ...

  6. 洛谷p3384【模板】树链剖分题解

    洛谷p3384 [模板]树链剖分错误记录 首先感谢\(lfd\)在课上调了出来\(Orz\) \(1\).以后少写全局变量 \(2\).线段树递归的时候最好把左右区间一起传 \(3\).写\(dfs\ ...

  7. 洛谷 P3384 【模板】树链剖分

    树链剖分 将一棵树的每个节点到它所有子节点中子树和(所包含的点的个数)最大的那个子节点的这条边标记为"重边". 将其他的边标记为"轻边". 若果一个非根节点的子 ...

  8. Luogu 3384 【模板】树链剖分

    题目描述 如题,已知一棵包含N个结点的树(连通且无环),每个节点上包含一个数值,需要支持以下操作: 操作1: 格式: 1 x y z 表示将树从x到y结点最短路径上所有节点的值都加上z 操作2: 格式 ...

  9. Luogu P3384 【【模板】树链剖分】

    转载请注明出处,部分内容引自banananana大神的博客 ~~别说你不知道什么是树~~╮(─▽─)╭(帮你百度一下) 先来回顾两个问题:1,将树从x到y结点最短路径上所有节点的值都加上z 这也是个模 ...

随机推荐

  1. asp.net .net4.0使用异步编程

    "; Action<object> ac = (object obj) => { Debug.WriteLine("睡眠开始:" + DateTime. ...

  2. JSP传递数组给JS的方法

    由于JSP页面的数组无法直接传到JS.所以采用以下方法来获取数组. <% String[] title = { "姓名 ", "学号 ", "性 ...

  3. DataSet和List 泛型之间互相转换 (转载)

    //DataSet与泛型集合间的互相转换 //利用反射机制将DataTable的字段与自定义类型的公开属性互相赋值. //注意:从DataSet到IList<T>的转换,自定义类型的公开属 ...

  4. mysqlslap工具测试mysql DB的性能

    mysqlslap的一个主要工作场景就是对数据库服务器做基准测试.     测试方法 1.测试工具:mysqlslap,mysqlslap是MySQL5.1.4之后自带的benchmark基准测试工具 ...

  5. Java字符串2

    if(str!= null && str.isEmpty()){ dao.get(str); } str.isEmpty判断字符串是否为空字符串

  6. Maven 生命周期 和插件

    1.3 生命周期1.3.1 什么是生命周期? Maven生命周期就是为了对所有的构建过程进行抽象和统一.包括项目清理.初始化.编译.打包.测试.部署等几乎所有构建步骤. 生命周期可以理解为构建工程的步 ...

  7. React & `event.persist()`

    React & event.persist() event.persist() https://reactjs.org/docs/events.html#event-pooling Tabs ...

  8. [OS] 进程间通信--管道

    管道是单向的.先进先出的.无结构的.固定大小的字节流,它把一个进程的标准输出和另一个进程的标准输入连接在一起.写进程在管道的尾端写入数据,读进程在管道的首端读出数据.数据读出后将从管道中移走,其它读进 ...

  9. [洛谷P4512]【模板】多项式除法

    题目大意:给定一个$n$次多项式$F(x)$和一个$m$次多项式$G(x)$,请求出多项式$Q(x),R(x)$,满足: 1. $Q(x)$次数为$n-m$,$R(x)$次数小于$m$2. $F(x) ...

  10. [NOI.AC省选模拟赛3.31] 星辰大海 [半平面交]

    题面 传送门 思路 懒得解释了......也是比较简单的结论 但是自己看到几何就退缩了...... 下周之内写一个计算几何的学习笔记! Code #include<iostream> #i ...