[洛谷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], ...
随机推荐
- 第一个struts2框架
编写步骤: 1.导入有关的包. 2.编写web.xml文件 3.写Action类 4.编写jsp 5.编写struts.xml web.xml <?xml version="1.0&q ...
- Struts 2的下载和安装
一.为Web应用增加Struts 2支持 下载和安装Struts 2步骤: 登录http://struts.apache.org/download.cgi站点,下载Struts 2的最新版,下载时有以 ...
- JavaWeb部分视频\2-12JSP,EL和JSTL
JavaWeb知识结构图 第3节 EL介绍和运算符 && 第4节 EL获取域中存储的数据 ## EL表达式 1. 概念:Expression Language 表达式语言 2. 作用: ...
- Ubuntu---不能打开 exfat 文件系统格式的 U盘解决方法
出现问题:今天把 U 盘插入 Ubuntu 系统的电脑中,打开 U 盘发现弹出 系统格式不支持 的提醒,无法进入 U 盘进行操作. 环境: Ubuntu18.04 TSL; 格式化为 exfat 文件 ...
- PAT Advanced 1069 The Black Hole of Numbers (20) [数学问题-简单数学]
题目 For any 4-digit integer except the ones with all the digits being the same, if we sort the digits ...
- 实现迭代器(\_\_next\_\_和\_\_iter\_\_)
目录 实现迭代器(__next__和__iter__) 一.简单示例 二.StopIteration异常版 三.模拟range 四.斐波那契数列 实现迭代器(__next__和__iter__) 一. ...
- Kafka及周边深度了解
之前介绍了使用官方脚本自动化启动一个Fabric网络,并且所有的证书都是通过官方的命令行工具cryptogen直接生成网络中的所有节点的证书.在开发环境可以这么简单进行,但是生成环境下还是需要我们自定 ...
- [CTS2019]随机立方体(容斥+组合数学)
这题七次方做法显然,但由于我太菜了,想了一会发现也就只会这么多,而且别的毫无头绪.发现直接做不行,那么,容斥! f[i]为至少i个极值的方案,然后这里需要一些辅助变量,a[i]表示选出i个三维坐标均不 ...
- << 和>> 的计算公式
在java中,一个数左移n位,就是将这个数乘以2的n次方,右移就是将这个数除以2的n次方. 如: 8>>2 = 2 (8/2^2) 15 << 3 = 120 (15*(2 ...
- oracle_(第三课)网络服务配置
1.打开Net Manager 2.开始配置 3.检测 4.SQL Developer 检测 新创数据库连接,连接类型选择 TNS ,若在网络别名中能看到MYORCL,则证明你成功了