原题链接

对于以u为根的子树,后代节点的dfn显然比他的dfn大,我们可以记录一下回溯到u的dfn,显然这两个dfn构成了一个连续区间,代表u及u的子树

剩下的就和树剖一样了

 #include<cstdio>
#include<algorithm>
#include<cstring>
#define N 100010
typedef long long ll;
using namespace std;
int ecnt,head[N],son[N],fa[N],sz[N],n,m,r,deep[N],pos[N],indx[N],tot,op,back[N],top[N];
ll val[N],P;
struct adj
{
int nxt,v;
}e[*N];
struct node
{
int l,r;
ll sum,lz;
}t[*N];
void add(int u,int v)
{
e[++ecnt].v=v;
e[ecnt].nxt=head[u];
head[u]=ecnt;
e[++ecnt].v=u;
e[ecnt].nxt=head[v];
head[v]=ecnt;
}
void dfs1(int x,int father,int dep)
{
deep[x]=dep,fa[x]=father,sz[x]=;
for (int i=head[x];i;i=e[i].nxt)
{
int v=e[i].v;
if (fa[x]==v) continue;
dfs1(v,x,dep+);
sz[x]+=sz[v];
if (sz[v]>sz[son[x]]) son[x]=v;
}
}
void dfs2(int x,int TOP)
{
top[x]=TOP;
pos[x]=++tot;
indx[tot]=x;
if (son[x]) dfs2(son[x],TOP);
for (int i=head[x];i;i=e[i].nxt)
{
int v=e[i].v;
if (v==fa[x] || v==son[x]) continue;
dfs2(v,v);
}
back[x]=tot;
}
void pushdown(int p)
{
if (t[p].l==t[p].r || !t[p].lz) return;
int w=t[p].lz;
t[p<<].sum=(t[p<<].sum+w*(t[p<<].r-t[p].l+)%P)%P;
t[p<<|].sum=(t[p<<|].sum+w*(t[p<<|].r-t[p<<|].l+)%P)%P;
t[p<<].lz+=w;
t[p<<].lz%=P;
t[p<<|].lz+=w;
t[p<<|].lz%=P;
t[p].lz=;
}
void pushup(int p)
{
t[p].sum=(t[p<<].sum+t[p<<|].sum)%P;
}
void build(int p,int l,int r)
{
t[p].l=l,t[p].r=r,t[p].lz=;
if (l!=r)
{
int mid=l+r>>;
build(p<<,l,mid);
build(p<<|,mid+,r);
pushup(p);
}
else
t[p].sum=val[indx[l]]%P;
}
void modify(int p,int l,int r,int w)
{
if (t[p].l==l && t[p].r==r)
{
t[p].sum+=w*(t[p].r-t[p].l+);
t[p].lz+=w;
return ;
}
pushdown(p);
int mid=t[p].l+t[p].r>>;
if (r<=mid) modify(p<<,l,r,w);
else if (l>mid) modify(p<<|,l,r,w);
else modify(p<<,l,mid,w),modify(p<<|,mid+,r,w);
pushup(p);
}
ll query(int p,int l,int r)
{
if (t[p].l==l && t[p].r==r)
return t[p].sum%P;
int mid=t[p].l+t[p].r>>;
pushdown(p);
if (r<=mid) return query(p<<,l,r)%P;
if (l>mid) return query(p<<|,l,r)%P;
return (query(p<<,l,mid)+query(p<<|,mid+,r))%P;
}
void pathInc(int u,int v,int w)
{
while (top[u]!=top[v])
{
if (deep[top[u]]<deep[top[v]]) swap(u,v);
modify(,pos[top[u]],pos[u],w);
u=fa[top[u]];
}
if (deep[u]>deep[v]) swap(u,v);
modify(,pos[u],pos[v],w);
}
ll pathQuery(int u,int v)
{
ll ret=;
while (top[u]!=top[v])
{
if (deep[top[u]]<deep[top[v]]) swap(u,v);
ret=(ret+query(,pos[top[u]],pos[u]))%P;
u=fa[top[u]];
}
if (deep[u]>deep[v]) swap(u,v);
return (ret+query(,pos[u],pos[v]))%P;
}
int main()
{
scanf("%d%d%d%lld",&n,&m,&r,&P);
for (int i=;i<=n;i++)
scanf("%lld",&val[i]);
for (int i=,u,v;i<n;i++)
scanf("%d%d",&u,&v),add(u,v);
dfs1(r,,);
dfs2(r,r);
build(,,n);
for (int i=,x,y,z;i<=m;i++)
{
scanf("%d",&op);
if (op==)
scanf("%d%d%d",&x,&y,&z),pathInc(x,y,z);
else if (op==)
scanf("%d%d",&x,&y),printf("%lld\n",pathQuery(x,y));
else if (op==)
scanf("%d%d",&x,&z),modify(,pos[x],back[x],z);
else scanf("%d",&x),printf("%lld\n",query(,pos[x],back[x]));
}
return ;
}

洛谷树剖模板题 P3384 | 树链剖分的更多相关文章

  1. 洛谷 P3373 【模板】线段树 2

    洛谷 P3373 [模板]线段树 2 洛谷传送门 题目描述 如题,已知一个数列,你需要进行下面三种操作: 将某区间每一个数乘上 xx 将某区间每一个数加上 xx 求出某区间每一个数的和 输入格式 第一 ...

  2. 洛谷P3372 【模板】线段树 1

    P3372 [模板]线段树 1 153通过 525提交 题目提供者HansBug 标签 难度普及+/提高 提交  讨论  题解 最新讨论 [模板]线段树1(AAAAAAAAA- [模板]线段树1 洛谷 ...

  3. 洛谷P3373 【模板】线段树 2

     P3373 [模板]线段树 2 47通过 186提交 题目提供者HansBug 标签 难度提高+/省选- 提交  讨论  题解 最新讨论 为啥WA(TAT) 题目描述 如题,已知一个数列,你需要进行 ...

  4. 洛谷 P3373 【模板】线段树 2 解题报告

    P3373 [模板]线段树 2 题目描述 如题,已知一个数列,你需要进行下面三种操作: 1.将某区间每一个数乘上\(x\) 2.将某区间每一个数加上\(x\) 3.求出某区间每一个数的和 输入输出格式 ...

  5. 洛谷 P3372 【模板】线段树 1

    P3372 [模板]线段树 1 题目描述 如题,已知一个数列,你需要进行下面两种操作: 1.将某区间每一个数加上x 2.求出某区间每一个数的和 输入输出格式 输入格式: 第一行包含两个整数N.M,分别 ...

  6. 洛谷—— P3372 【模板】线段树 1

    P3372 [模板]线段树 1 题目描述 如题,已知一个数列,你需要进行下面两种操作: 1.将某区间每一个数加上x 2.求出某区间每一个数的和 输入输出格式 输入格式: 第一行包含两个整数N.M,分别 ...

  7. 洛谷——P3373 【模板】线段树 2&& B 数据结构

    P3373 [模板]线段树 2 题目描述 如题,已知一个数列,你需要进行下面三种操作: 1.将某区间每一个数乘上x 2.将某区间每一个数加上x 3.求出某区间每一个数的和 线段树维护区间乘法 1.如何 ...

  8. 洛谷 P3373 【模板】线段树 2 题解

    P3373 [模板]线段树 2 题目描述 如题,已知一个数列,你需要进行下面三种操作: 1.将某区间每一个数乘上x 2.将某区间每一个数加上x 3.求出某区间每一个数的和 输入格式 第一行包含三个整数 ...

  9. 洛谷P3373 【模板】线段树 2 && P2023 [AHOI2009]维护序列——题解

    题目传送: P3373 [模板]线段树 2  P2023 [AHOI2009]维护序列 该题较传统线段树模板相比多了一个区间乘的操作.一提到线段树的区间维护问题,就自然想到了“懒标记”:为了降低时间复 ...

随机推荐

  1. C#进阶学习笔记(个人整理)

    学习笔记 第一章: 一.回顾数组 1.变量 : 只能存储一个数据 2.数组 :存储固定大小的相同类型的数据 3.对象 : 存储多个相同/不同类型的数据 4.集合 : 特殊的容器,存储N个相同/不同类型 ...

  2. nuxt.config有关router配置

    这里只说明一个属性,其他属性移步官方文档 https://zh.nuxtjs.org/api/configuration-router extendRoutes   官方说明: 你可以通过 exten ...

  3. dts--framework(三)

    tester.py class Tester(Crb) 00. __init__(self, crb, serializer) 01.init_ext_gen(self) 02.set_re_run( ...

  4. Manacher算法:求解最长回文字符串,时间复杂度为O(N)

    原文转载自:http://blog.csdn.net/yzl_rex/article/details/7908259 回文串定义:"回文串"是一个正读和反读都一样的字符串,比如&q ...

  5. JZOJ 3534. 【NOIP2013提高组day1】货车运输

    Description A 国有 n 座城市,编号从 1 到 n,城市之间有 m 条双向道路.每一条道路对车辆都有重量限制,简称限重.现在有 q 辆货车在运输货物,司机们想知道每辆车在不超过车辆限重的 ...

  6. 各种Nand的总结

    1. 微观 NAND闪存NAND是非易失性存储技术,NAND闪存由多个存放以位(bit)为单位的单元构成,这些位通过电荷被打开或关闭,如何组织这些开关单元来储存在SSD上的数据,也决定了NAND闪存的 ...

  7. C语言进阶——分支语句06

    if分支语句分析: if语句用于根据条件选择执行语句 else不能独立存在且总是与在它之前的最近if相匹配 esle语句后可以连接其他if语句 用法如下: if(condition) { //stat ...

  8. [洛谷1156]垃圾陷阱(DP)

    [Luogu1156] f[i]表示高度为i时的存活时间 Code #include <cstdio> #include <algorithm> #define N 110 u ...

  9. 14,vue+uwsgi+nginx部署路飞学城

    有一天,老男孩的苑日天给我发来了两个神秘代码,听说是和mjj的结晶 超哥将这两个代码,放到了一个网站上,大家可以自行下载 路飞学城django代码 https://files.cnblogs.com/ ...

  10. Linux下单机安装部署kafka及代码实现

    技术交流群:233513714 这几天研究了kafka的安装及使用,在网上找了很多教程但是均以失败告终,直到最后想起网络方面的问题最终才安装部署成功,下面就介绍一下kafka的安装部署及代码实现 一. ...