题目传送门

显然是一道模板题。

然而索引出现了错误,狂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. UML-领域模型-属性

    1.属性预览 2.导出属性是什么? 3.属性使用什么样的数据类型? 常见的数据类型:boolean.Date.String(Text).Integer 其他常见的:SKU.枚举类型等 而在java类中 ...

  2. 2019年java后端年终总结(六年开发经验),送给正在努力的你

    长大之后,时间总是过得飞快,转眼之间,今年已经只剩下1天了.小时候总感觉遥不可及.只在科幻小说里面出现的2020年,已经开始进入蓄力期了. 这篇文章主要和大家聊一聊分析2019年java技术的更新给大 ...

  3. PTA 自测-4 Have Fun with Numbers

    #include<iostream> #include<string> #include<cstring> #include<vector> using ...

  4. java内存区域与内存溢出异常(1)

    一. 运行时数据区域 java虚拟机在执行Java程序的过程中,会把它所管理的内存划分为若干个不同的数据区域偶 1.程序计数器 程序计数器是一块较小的内存空间,作用是当前线程所执行的字节码的行号指示器 ...

  5. 配置完aop不能返回json

    遇到一个bug,配置了记录controller层的aop,后来发现是因为我aop是写在controller层(在springmvc的容器中)而开启aop配置却写在spring中,所以不起作用,需要在s ...

  6. 用最小的空间复杂度找出一个长度为n的数组且数据中的元素是[0,n-1]中任一个重复的数据。

    用最小的空间复杂度找出一个长度为n的数组且数据中的元素是[0,n-1]中任一个重复的数据. 比如:[1, 2, 3, 3, 2, 2, 6, 7, 8, 9] 中 2 or 3 分析:这道题目,实现比 ...

  7. c++ 语言几个坑

    #include <iostream> int main(){ int i = 1; switch (i){ case 1 : int j ; j = 1; break; case 2: ...

  8. DNA methylation|Transcription factors|PTM|Chromosome conformation|表观遗传学测序技术

    生物医疗大数据-DNA element functions and identification Genetic vs epigenetic GENETICS  遗传学 DNA Code: 64 tr ...

  9. ZJNU 1133 - Subset sequence——中级

    推出n=1到4时,An排列的种类数分别为1 4 15 64可得(1+1)*2=4(4+1)*3=15(15+1)*4=64...故用一数列r[n]记录An的种类总数当n=3时,列举出以下15种从大到小 ...

  10. iOS 部分API理解

    - (void)viewDidLoad { [super viewDidLoad]; // Do any additional setup after loading the view, typica ...