题目链接:https://www.luogu.org/problemnew/show/P3384

诶又给自己留了个坑..不想写线段树一大理由之前的模板变量名太长

#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#define lson left, mid, rt<<1
#define rson mid + 1, right, rt<<1|1
#define ll long long
using namespace std;
const int maxn = 200000 + 10;
ll n, m, root, mod;
ll node[maxn], num;
ll fa[maxn], dep[maxn], size[maxn], son[maxn], top[maxn], seg[maxn], rev[maxn];
ll res;
struct edge{
ll from, to, next;
}e[maxn<<2];
ll head[maxn], cnt;
//-------------------------------------------------------
ll tree[maxn<<2], lazy[maxn<<2];
void PushUP(ll rt)
{
tree[rt] = (tree[rt<<1] + tree[rt<<1|1])%mod;
}
void build(ll left, ll right, ll rt)
{
if(left == right)
{
tree[rt] = rev[left];
tree[rt] = tree[rt]%mod;
return;
}
ll mid = (left + right) >> 1;
build(lson);
build(rson);
PushUP(rt);
}
void PushDOWN(ll left, ll right, ll rt, ll mid)
{
lazy[rt<<1] += lazy[rt];
lazy[rt<<1|1] += lazy[rt];
tree[rt<<1] += ((mid - left + 1)*lazy[rt])%mod;
tree[rt<<1|1] += ((right - mid)*lazy[rt])%mod;
lazy[rt] = 0;
}
ll query(ll l, ll r, ll left, ll right, ll rt)
{
ll res = 0;
if(l <= left && r >= right)
{
return tree[rt]%mod;
}
ll mid = (left + right)>>1;
if(lazy[rt]) PushDOWN(left, right, rt, mid);
if(l <= mid) res += query(l, r, lson);
if(r > mid) res += query(l, r, rson);
return res;
}
void update(ll l, ll r, ll add, ll left, ll right, ll rt)
{
if(l <= left && r >= right)
{
lazy[rt] += add;
tree[rt] += (right - left + 1)*add;
return;
}
ll mid = (left + right)>>1;
PushDOWN(left, right, rt, mid);
if(l <= mid) update(l, r, add, lson);
if(r > mid) update(l, r, add, rson);
PushUP(rt);
}
//------------------------------------------------
void add(ll u, ll v)
{
e[++cnt].from = u;
e[cnt].next = head[u];
e[cnt].to = v;
head[u] = cnt;
}
void dfs1(ll u, ll f, ll d)
{
ll maxson = -1;
size[u] = 1;
fa[u] = f;
dep[u] = d;
for(ll i = head[u]; i != -1; i = e[i].next)
{
ll v = e[i].to;
if(v != f)
{
dfs1(v, u, d + 1);
size[u] += size[v];
if(size[v] > maxson) son[u] = v, maxson = size[v];
}
}
}
void dfs2(ll u, ll t)
{
seg[u] = ++num;
rev[num] = node[u];
top[u] = t;
if(!son[u]) return;
dfs2(son[u], t);
for(ll i = head[u]; i != -1; i = e[i].next)
{
ll v = e[i].to;
if(fa[u] == v || son[u] == v) continue;
dfs2(v, v);
}
}
ll qRange(ll x, ll y)
{
ll ans = 0;
while(top[x] != top[y])
{
if(dep[top[x]] < dep[top[y]]) swap(x, y);
res = 0;
res = query(seg[top[x]], seg[x], 1, n, 1);
ans = (ans + res)%mod;
x = fa[top[x]];
}
if(dep[x] > dep[y]) swap(x, y);
res = 0;
res = query(seg[x], seg[y], 1, n, 1);
ans = (ans + res)%mod;
return ans;
}
void updRange(ll x, ll y, ll k)
{
k = k%mod;
while(top[x] != top[y])
{
if(dep[top[x]] < dep[top[y]]) swap(x, y);
update(seg[top[x]], seg[x], k, 1, n, 1);
x = fa[top[x]];
}
if(dep[x] > dep[y]) swap(x, y);
update(seg[x], seg[y], k, 1, n, 1);
}
ll qSon(ll x)
{
res = 0;
res = query(seg[x], seg[x]+size[x]-1, 1, n, 1);
return res;
}
ll updSon(ll x, ll k)
{
update(seg[x], seg[x]+size[x]-1, k, 1, n, 1);
}
int main()
{
memset(head, -1, sizeof(head));
scanf("%lld%lld%lld%lld",&n,&m,&root,&mod);
for(ll i = 1; i <= n; i++)
scanf("%lld",&node[i]);
for(ll i = 1; i < n; i++)
{
ll u, v;
scanf("%lld%lld",&u,&v);
add(u, v), add(v, u);
}
dfs1(root, 0, 1);
dfs2(root, root);
build(1,n,1);
for(ll i = 1; i <= m; i++)
{
ll opt, x, y, z;
scanf("%lld",&opt);
if(opt == 1)
{
scanf("%lld%lld%lld",&x,&y,&z);
updRange(x, y, z);
}
if(opt == 2)
{
scanf("%lld%lld",&x,&y);
printf("%lld\n",qRange(x, y)%mod);
}
if(opt == 3)
{
scanf("%lld%lld",&x,&y);
updSon(x, y);
}
if(opt == 4)
{
scanf("%lld",&x);
printf("%lld\n",qSon(x)%mod);
}
}
return 0;
}

【luogu P3384 树链剖分】 模板的更多相关文章

  1. 洛谷 P3384 树链剖分(模板题)

    题目描述 如题,已知一棵包含N个结点的树(连通且无环),每个节点上包含一个数值,需要支持以下操作: 操作1: 格式: 1 x y z 表示将树从x到y结点最短路径上所有节点的值都加上z 操作2: 格式 ...

  2. Luogu - P3384 树链剖分 [挂模板专用]

    题意:请码个树剖模板支持子树区间加/查询和路径加/查询 纯练手 盲敲技能++ 以后网络赛复制模板速度++++ 对链操作时注意方向 #include<bits/stdc++.h> #defi ...

  3. P3384——树链剖分&&模板

    题目描述 链接 如题,已知一棵包含N个结点的树(连通且无环),每个节点上包含一个数值,需要支持以下操作: 操作1: 格式: 1 x y z 表示将树从x到y结点最短路径上所有节点的值都加上z 操作2: ...

  4. BZOJ 2243 染色 | 树链剖分模板题进阶版

    BZOJ 2243 染色 | 树链剖分模板题进阶版 这道题呢~就是个带区间修改的树链剖分~ 如何区间修改?跟树链剖分的区间询问一个道理,再加上线段树的区间修改就好了. 这道题要注意的是,无论是线段树上 ...

  5. 算法复习——树链剖分模板(bzoj1036)

    题目: 题目背景 ZJOI2008 DAY1 T4 题目描述 一棵树上有 n 个节点,编号分别为 1 到 n ,每个节点都有一个权值 w .我们将以下面的形式来要求你对这棵树完成一些操作:I.CHAN ...

  6. Hdu 5274 Dylans loves tree (树链剖分模板)

    Hdu 5274 Dylans loves tree (树链剖分模板) 题目传送门 #include <queue> #include <cmath> #include < ...

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

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

  8. bzoj1036 [ZJOI2008]树的统计Count 树链剖分模板题

    [ZJOI2008]树的统计Count Description 一棵树上有n个节点,编号分别为1到n,每个节点都有一个权值w.我们将以下面的形式来要求你对这棵树完成 一些操作: I. CHANGE u ...

  9. 洛谷P3384 树链剖分

    如题,已知一棵包含N个结点的树(连通且无环),每个节点上包含一个数值,需要支持以下操作: 操作1: 格式: 1 x y z 表示将树从x到y结点最短路径上所有节点的值都加上z 操作2: 格式: 2 x ...

随机推荐

  1. 使用jxl读取excel内容,并转换成Json,用于Datagrid

    一.上传excel文件,得到InputStream,由InputStream得到Jxl中的Workbook,取出内容,存到二维数组中. 1.使用 Jquery Uploadify 插件(http:// ...

  2. pip使用的基本命令

    基本的命令解释,如下图: 安装 sudo easy_install pip 列出已安装的包 pip freeze or pip list 导出requirements.txt pip freeze & ...

  3. 新版本火狐 ,Chrome不支持showModalDialog解决办法

    平常的网站中,有时我们会希望使用者按下按钮后开启一个保持在原窗口前方的子窗口,在IE中,我们可以使用showModalDialog来达成,但是chrome早就不支持showModalDialog,最近 ...

  4. 通过js操作样式(评分)

    <style> td{ font-size:50px; color:yellow; cursor:pointer; } </style> <script type=&qu ...

  5. python学习(七)--豆瓣爬取电影名,评分以及演员

    import requestsimport re #爬取豆瓣电影排名pageNum = int(input("要查看第几页电影分数:"))#已知豆瓣默认每页展示20条#url= & ...

  6. document.write()重写问题

    document.write(); 可用于重写给某个元素追加内容; 当document.write(); 用于JS文件中,会重写整个页面,解决这个问题有多种方法. 重写原因:当onload的时候执行 ...

  7. vbScript: 编号成生不夠位數前面加零

    '编号成生Geovin Du '不夠位數前面加零 塗聚文 Function getStringlen(str,lenint) so="" itop=0 slen=Len(str) ...

  8. 10th week task -2 Object 的起源

    Objective-C与C++.Java等面向对象语言类似,不过很多方面有所差别.若是用过另一种面向对象语言,那么就能理解Objective-C所用的许多范式与模版了.然而语法上也许会显得陌生,因为该 ...

  9. <form> 标签的 enctype 属性

    值 描述 application/x-www-form-urlencoded 在发送前编码所有字符(默认) multipart/form-data 不对字符编码.在使用包含文件上传控件的表单时,必须使 ...

  10. Internet Of Things