[洛谷P3384] [模板] 树链剖分
显然是一道模板题。
然而索引出现了错误,狂wa不止。
感谢神犇Dr_J指正。%%%orz。
建线段树的时候,第44行。
把sum[p]=bv[pos[l]]%mod;打成了sum[p]=bv[in[l]]%mod;
忘了要用反映射搞一下......
树链剖分,从每个节点的儿子中,找出子树最大的一个作为重儿子。
然后以此将树链分成轻链和重链。
之后dfs一遍求出树链剖分序。
树链剖分序不仅保证子树内节点的编号在序列上连续,还保证一条重链上的节点的编号连续。
用一个线段树维护一下。
更改/询问子树的时候就是区间修改/查询区间和。
更改/询问树链的时候就是一步一步跳重链,每次一个区间修改/查询区间和。
#include<cstdio>
#include<cstring>
#include<algorithm>
#define ll long long
using namespace std; int n,m,root;
ll mod;
ll bv[];
int hd[],to[],nx[],ec;
int sz[],f[],d[];
int son[],tp[];
int in[],out[],pc,pos[];
int lb[],rb[];
ll sum[],lz[]; void edge(int af,int at)
{
to[++ec]=at;
nx[ec]=hd[af];
hd[af]=ec;
} void pushup(int p)
{
sum[p]=((sum[p<<]+sum[p<<|])%mod+mod)%mod;
} void pushdown(int p)
{
if(!lz[p])return;
sum[p<<]=((sum[p<<]+(rb[p<<]-lb[p<<]+)%mod*lz[p]%mod)%mod+mod)%mod;
sum[p<<|]=((sum[p<<|]+(rb[p<<|]-lb[p<<|]+)%mod*lz[p]%mod)%mod+mod)%mod;
lz[p<<]=((lz[p<<]+lz[p])%mod+mod)%mod;
lz[p<<|]=((lz[p<<|]+lz[p])%mod+mod)%mod;
lz[p]=;
} void build(int p,int l,int r)
{
lb[p]=l,rb[p]=r;
if(l==r)
{
sum[p]=bv[pos[l]]%mod;
return;
}
int mid=(l+r)>>;
build(p<<,l,mid);
build(p<<|,mid+,r);
pushup(p);
} void add(int p,int l,int r,ll v)
{
if(lb[p]>=l&&rb[p]<=r)
{
sum[p]=(sum[p]+(rb[p]-lb[p]+)%mod*v%mod)%mod;
lz[p]=(lz[p]+v)%mod;
return;
}
pushdown(p);
int mid=(lb[p]+rb[p])>>;
if(l<=mid)add(p<<,l,r,v);
if(r>mid)add(p<<|,l,r,v);
pushup(p);
} ll query(int p,int l,int r)
{
if(lb[p]>=l&&rb[p]<=r)return sum[p];
pushdown(p);
int mid=(lb[p]+rb[p])>>;
ll ret=;
if(l<=mid)ret=((ret+query(p<<,l,r))%mod+mod)%mod;
if(r>mid)ret=((ret+query(p<<|,l,r))%mod+mod)%mod;
return ret;
} void pre(int p,int fa)
{
d[p]=d[fa]+,f[p]=fa,sz[p]=;
for(int i=hd[p];i;i=nx[i])
{
if(to[i]==fa)continue;
pre(to[i],p);
sz[p]+=sz[to[i]];
if(sz[to[i]]>sz[son[p]])son[p]=to[i];
}
} void dfs(int p)
{
in[p]=++pc;
pos[pc]=p;
if(p==son[f[p]])tp[p]=tp[f[p]];
else tp[p]=p;
if(son[p])dfs(son[p]);
for(int i=hd[p];i;i=nx[i])
if(to[i]!=f[p]&&to[i]!=son[p])dfs(to[i]);
out[p]=pc;
} int main()
{
scanf("%d%d%d%lld",&n,&m,&root,&mod);
for(int i=;i<=n;i++)scanf("%lld",&bv[i]);
for(int i=;i<n;i++)
{
int ff,tt;
scanf("%d%d",&ff,&tt);
edge(ff,tt),edge(tt,ff);
}
pre(root,root);
dfs(root);
build(,,n);
for(int i=;i<=m;i++)
{
int op;
scanf("%d",&op);
if(op==)
{
int x,y;
ll z;
scanf("%d%d%lld",&x,&y,&z);
z%=mod;
while(tp[x]!=tp[y])
{
if(d[tp[x]]<d[tp[y]])swap(x,y);
add(,in[tp[x]],in[x],z);
x=f[tp[x]];
}
if(d[x]>d[y])swap(x,y);
add(,in[x],in[y],z);
}
if(op==)
{
int x,y;
scanf("%d%d",&x,&y);
ll ans=;
while(tp[x]!=tp[y])
{
if(d[tp[x]]<d[tp[y]])swap(x,y);
ans=((ans+query(,in[tp[x]],in[x]))%mod+mod)%mod;
x=f[tp[x]];
}
if(d[x]>d[y])swap(x,y);
ans=((ans+query(,in[x],in[y]))%mod+mod)%mod;
printf("%lld\n",ans);
}
if(op==)
{
int x;
ll z;
scanf("%d%lld",&x,&z);
z%=mod;
add(,in[x],out[x],z);
}
if(op==)
{
int x;
scanf("%d",&x);
ll ans=query(,in[x],out[x]);
printf("%lld\n",ans);
}
}
return ;
}
[洛谷P3384] [模板] 树链剖分的更多相关文章
- [luogu P3384] [模板]树链剖分
[luogu P3384] [模板]树链剖分 题目描述 如题,已知一棵包含N个结点的树(连通且无环),每个节点上包含一个数值,需要支持以下操作: 操作1: 格式: 1 x y z 表示将树从x到y结点 ...
- 洛谷P3979 遥远的国度 树链剖分+分类讨论
题意:给出一棵树,这棵树每个点有权值,然后有3种操作.操作一:修改树根为rt,操作二:修改u到v路径上点权值为w,操作三:询问以rt为根x子树的最小权值. 解法:如果没有修改树根操作那么这题就是树链剖 ...
- 洛谷 P4114 Qtree1 树链剖分
目录 题面 题目链接 题目描述 输入输出格式 输入格式: 输出格式: 输入输出样例 输入样例: 输出样例: 说明 说明 思路 Change Query AC代码 总结 题面 题目链接 P4114 Qt ...
- 洛谷.4114.Qtree1(树链剖分)
题目链接 模板题都错了这么多次.. //边权赋到点上 树剖模板 //注意LCA.链的顶端不能统计到答案! #include <cstdio> #include <cctype> ...
- 洛谷3384&bzoj1036树链剖分
值得注意的是: 一个点的子树是存在一起的...也就是说我们修改子树的时候只用... /********************************************************* ...
- P3384 [模板] 树链剖分
#include <bits/stdc++.h> using namespace std; typedef long long ll; int n, m, rt, mod, cnt, to ...
- luoguP3384 [模板]树链剖分
luogu P3384 [模板]树链剖分 题目 #include<iostream> #include<cstdlib> #include<cstdio> #inc ...
- 【Luogu P3384】树链剖分模板
树链剖分的基本思想是把一棵树剖分成若干条链,再利用线段树等数据结构维护相关数据,可以非常暴力优雅地解决很多问题. 树链剖分中的几个基本概念: 重儿子:对于当前节点的所有儿子中,子树大小最大的一个儿子就 ...
- 模板 树链剖分BFS版本
//点和线段树都从1开始 //边使用vector vector<int> G[maxn]; ],num[maxn],iii[maxn],b[maxn],a[maxn],top[maxn], ...
随机推荐
- windows 安装Bitcoin Core使用
1.官网下载https://bitcoin.org/en/download 选择Windows 其他系统就选择对应的就好 2.双击安装完过后,进入bin目录,打开bitcoin-qt.exe运行,提 ...
- PAT Advanced 1096 Consecutive Factors (20) [数学问题-因子分解 逻辑题]
题目 Among all the factors of a positive integer N, there may exist several consecutive numbers. For e ...
- Java搭建WebSocket的两种方式
下面分别介绍搭建方法:一.直接使用Java EE的api进行搭建.一共3个步骤:1.添加依赖<dependency> <groupId>javax</groupId ...
- Anaconda 安装 TensorFlow ImportError:DLL加载失败,错误代码为-1073741795
错误再现 环境: 使用Anaconda 中 conda 4.6.2, Python 3.7版本 Windows 7 操作系统 CPU: Intel i5 原始安装过程 直接在CMD中,安装链接 中的方 ...
- 关于Spring的使用总结
简介 Spring框架是一种轻量级的.一站式的企业级开发解决方案 框架(framework):是一组设计思想.规范.API的精心组合,专门用来解决某一层次或领域的问题 轻量级(lightweight) ...
- DRF框架之ModelSerializer序列化器
ModelSerializer是Serializer的子类,序列化和反序列化跟Serializer一样. ModelSerializer与常规的Serializer相同,但提供了: 基于模型类自动生成 ...
- Python—守护进程管理工具(Supervisor)
一.前言简介 1.Supervisor 是一个 Python 开发的 client/server 系统,可以管理和监控类 UNIX 操作系统上面的进程.可以很方便的用来启动.重启.关闭进程(不仅仅是 ...
- 【ccf- csp201412-2】z字形扫描
//ccf-Z字形扫描 #include<iostream> #include<cmath> using namespace std; #define N 500 int ma ...
- index|substr
#!/usr/bin/perl use strict; use warnings; $_ = 'duwanxkm,c.,df;oq123@#!@%$#^'; my $d ='d';my $o = 'o ...
- Mac中Apache常用命令
Apache常用命令记录,还是记一下吧,总是忘记. Apache常用命令: # sudo apachectl start // 启动Apache服务 # sudo apachectl stop // ...