「模板」 树链剖分 HLD
「模板」 树链剖分 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的更多相关文章
- P3384 【模板】树链剖分
P3384 [模板]树链剖分 题目描述 如题,已知一棵包含N个结点的树(连通且无环),每个节点上包含一个数值,需要支持以下操作: 操作1: 格式: 1 x y z 表示将树从x到y结点最短路径上所有节 ...
- luogu3384 【模板】树链剖分
P3384 [模板]树链剖分 题目描述 如题,已知一棵包含N个结点的树(连通且无环),每个节点上包含一个数值,需要支持以下操作: 操作1: 格式: 1 x y z 表示将树从x到y结点最短路径上所有节 ...
- 【算法学习】【洛谷】树链剖分 & P3384 【模板】树链剖分 P2146 软件包管理器
刚学的好玩算法,AC2题,非常开心. 其实很早就有教过,以前以为很难就没有学,现在发现其实很简单也很有用. 更重要的是我很好调试,两题都是几乎一遍过的. 介绍树链剖分前,先确保已经学会以下基本技巧: ...
- 洛谷 P3384 【模板】树链剖分-树链剖分(点权)(路径节点更新、路径求和、子树节点更新、子树求和)模板-备注结合一下以前写的题目,懒得写很详细的注释
P3384 [模板]树链剖分 题目描述 如题,已知一棵包含N个结点的树(连通且无环),每个节点上包含一个数值,需要支持以下操作: 操作1: 格式: 1 x y z 表示将树从x到y结点最短路径上所有节 ...
- 树链剖分 - Luogu 3384【模板】树链剖分
[模板]树链剖分 题目描述 已知一棵包含N个结点的树(连通且无环),每个节点上包含一个数值,需要支持以下操作: 操作1: 格式: 1 x y z 表示将树从x到y结点最短路径上所有节点的值都加上z 操 ...
- 洛谷p3384【模板】树链剖分题解
洛谷p3384 [模板]树链剖分错误记录 首先感谢\(lfd\)在课上调了出来\(Orz\) \(1\).以后少写全局变量 \(2\).线段树递归的时候最好把左右区间一起传 \(3\).写\(dfs\ ...
- 洛谷 P3384 【模板】树链剖分
树链剖分 将一棵树的每个节点到它所有子节点中子树和(所包含的点的个数)最大的那个子节点的这条边标记为"重边". 将其他的边标记为"轻边". 若果一个非根节点的子 ...
- Luogu 3384 【模板】树链剖分
题目描述 如题,已知一棵包含N个结点的树(连通且无环),每个节点上包含一个数值,需要支持以下操作: 操作1: 格式: 1 x y z 表示将树从x到y结点最短路径上所有节点的值都加上z 操作2: 格式 ...
- Luogu P3384 【【模板】树链剖分】
转载请注明出处,部分内容引自banananana大神的博客 ~~别说你不知道什么是树~~╮(─▽─)╭(帮你百度一下) 先来回顾两个问题:1,将树从x到y结点最短路径上所有节点的值都加上z 这也是个模 ...
随机推荐
- 【转】MySQLroot用户忘记密码解决方案(安全模式,修改密码的三种方式)
文章出自:http://www.2cto.com/database/201412/358128.html 1.关闭正在运行的MySQL2.启动MySQL的安全模式,命令如下: ? 1 mysqld - ...
- Java之I/O流(第1部分)
Java 中的I/O流: 1. 输入/输出流原理: 如下图所示:在 java 程序中,对于数据的输入/输出操作以“流”(Stream)的方式进行:J2SDK 提供了各种各样的“流”类,用来获取不同种类 ...
- 关于char, wchar_t, TCHAR, _T(),L,宏 _T、TEXT,_TEXT、L
char :单字节变量类型,最多表示256个字符, wchar_t :宽字节变量类型,用于表示Unicode字符, 它实际定义在<string.h>里:typedef unsigned s ...
- VS2005、VS2008中的快捷键、组合键大全
Ctrl+E,D ----格式化全部代码 Ctrl+E,F ----格式化选中的代码 CTRL + SHIFT + B生成解决方案 CTRL + F7 生成编译 CTRL + O 打开文件 CTRL ...
- .net控制台程序Program args参数解析
一直很有疑问在控制台程序的Main函数中为什么会有个string[] args的参数,又没有什么用. static void Main(string[] args) { } 这几天需要将一个控制台程序 ...
- zabbix概念
Zabbix是一个企业级的.开源的.分布式监控解决方案. Zabbix可以监控网络和服务的监控状况. Zabbix利用灵活的告警机制,允许用户对事件发送基于Email的告警. 这样可以保证快速的对问题 ...
- phpcms黄页,不能选择行业。解决办法
用phpcms黄页模块,发布产品的时候.不能选择 产品分类,点开之后,啥都没有,是空的. 这个是因为:js的问题. 解决办法:将 网站根目录的 js 文件中的两个文件,更换为 官方的两个js文件.即可 ...
- 使用图片方式显示email地址
import java.awt.Color; import java.awt.Font; import java.awt.FontMetrics; import java.awt.Graphics2D ...
- winform中文本框添加拖拽功能
对一个文本框添加拖拽功能: private void txtFolder_DragEnter(object sender, DragEventArgs e) { if (e.Data.GetDataP ...
- Python面向对象—类的继承
一个子类可以继承父类的所有属性,不管是父类的数据属性还是方法. class Father(object): num = 0 def __init__(self): print "I'm Pa ...