题目传送门

显然是一道模板题。

然而索引出现了错误,狂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] [模板] 树链剖分的更多相关文章

  1. [luogu P3384] [模板]树链剖分

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

  2. 洛谷P3979 遥远的国度 树链剖分+分类讨论

    题意:给出一棵树,这棵树每个点有权值,然后有3种操作.操作一:修改树根为rt,操作二:修改u到v路径上点权值为w,操作三:询问以rt为根x子树的最小权值. 解法:如果没有修改树根操作那么这题就是树链剖 ...

  3. 洛谷 P4114 Qtree1 树链剖分

    目录 题面 题目链接 题目描述 输入输出格式 输入格式: 输出格式: 输入输出样例 输入样例: 输出样例: 说明 说明 思路 Change Query AC代码 总结 题面 题目链接 P4114 Qt ...

  4. 洛谷.4114.Qtree1(树链剖分)

    题目链接 模板题都错了这么多次.. //边权赋到点上 树剖模板 //注意LCA.链的顶端不能统计到答案! #include <cstdio> #include <cctype> ...

  5. 洛谷3384&bzoj1036树链剖分

    值得注意的是: 一个点的子树是存在一起的...也就是说我们修改子树的时候只用... /********************************************************* ...

  6. P3384 [模板] 树链剖分

    #include <bits/stdc++.h> using namespace std; typedef long long ll; int n, m, rt, mod, cnt, to ...

  7. luoguP3384 [模板]树链剖分

    luogu P3384 [模板]树链剖分 题目 #include<iostream> #include<cstdlib> #include<cstdio> #inc ...

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

    树链剖分的基本思想是把一棵树剖分成若干条链,再利用线段树等数据结构维护相关数据,可以非常暴力优雅地解决很多问题. 树链剖分中的几个基本概念: 重儿子:对于当前节点的所有儿子中,子树大小最大的一个儿子就 ...

  9. 模板 树链剖分BFS版本

    //点和线段树都从1开始 //边使用vector vector<int> G[maxn]; ],num[maxn],iii[maxn],b[maxn],a[maxn],top[maxn], ...

随机推荐

  1. 65)STL中string的知识

    1)代码展示: string是一个类,只不过封装了 char*  而且还封装了  很多的字符串操作函数 2)string类的初始化: string的构造函数 ²  默认构造函数: string();  ...

  2. 微信小程序2048开发进度(二)

    对小程序首先进行游戏架构: 实现小程序的首页展示界面,初始化棋盘格,以及NEW GAME按钮,成绩展现.

  3. JavaScript学习笔记 - 入门篇(1)- 准备

    为什么学习JavaScript 一.你知道,为什么JavaScript非常值得我们学习吗? 所有主流浏览器都支持JavaScript. 目前,全世界大部分网页都使用JavaScript. 它可以让网页 ...

  4. SLAM领域资源链接

    半闲居士高翔博客: https://www.cnblogs.com/gaoxiang12/ 视觉大佬冯兵博客: http://www.fengbing.net/ SLAMCN http://www.s ...

  5. 【python】两行代码实现近百年的正反日期查询--20200202

    到2020年了.有个日期也火了,记得上一次还是2011年11月2日.为啥捏,因为日期写成数字形式 正反是一样的. 2020年也有一个这样的日期.20200202:2020年2月2日. 于是乎想写一段代 ...

  6. jdk8下载地址

    http://www.oracle.com/technetwork/java/javase/downloads/jdk8-downloads-2133151.html Java SE Binaries ...

  7. 17.3.16---python内建函数

    内置函数,无需import,任何时候都可以直接被使用 1------ Python针对众多的类型,提供了众多的内建函数来处理(内建是相对于导入import来说的,后面学习到包package时,将会介绍 ...

  8. 发布订阅--SQLServer复制需要有实际的服务器名称才能连接到服务器,请指定实际的服务器名

    最近在学习SQL SERVER的高级复制技术的时候,遇到一个小问题,就是用本地SQL SERVER连接服务器的数据库时,在查看复制功能的发布服务器时,连接不上,弹出一个错误提示框架,如下: 原来在自己 ...

  9. ZJNU 1130 - 龟兔赛跑——中高级

    只需求出乌龟最短耗时跟兔子耗时比即可将起点 0 和终点 N+1 也看做充电站,进行动态规划对第i个点进行动态规划,则可以得到状态转移方程为dp[i] = max{dp[j]+time[i][j]} j ...

  10. JavaScript 的数据结构与算法

    1数组 1.1方法列表 数组的常用方法如下: concat: 链接两个或者更多数据,并返回结果. every: 对数组中的每一项运行给定的函数,如果该函数对每一项都返回true,则返回true. fi ...