题目描述

如题,已知一棵包含N个结点的树(连通且无环),每个节点上包含一个数值,需要支持以下操作:

操作1: 格式: 1 x y z 表示将树从x到y结点最短路径上所有节点的值都加上z

操作2: 格式: 2 x y 表示求树从x到y结点最短路径上所有节点的值之和

操作3: 格式: 3 x z 表示将以x为根节点的子树内所有节点值都加上z

操作4: 格式: 4 x 表示求以x为根节点的子树内所有节点值之和

输入输出格式

输入格式:

第一行包含4个正整数N、M、R、P,分别表示树的结点个数、操作个数、根节点序号和取模数(即所有的输出结果均对此取模)。

接下来一行包含N个非负整数,分别依次表示各个节点上初始的数值。

接下来N-1行每行包含两个整数x、y,表示点x和点y之间连有一条边(保证无环且连通)

接下来M行每行包含若干个正整数,每行表示一个操作,格式如下:

操作1: 1 x y z

操作2: 2 x y

操作3: 3 x z

操作4: 4 x

输出格式:

输出包含若干行,分别依次表示每个操作2或操作4所得的结果(对P取模

输入输出样例

输入样例#1: 复制

5 5 2 24
7 3 7 8 0
1 2
1 5
3 1
4 1
3 4 2
3 2 2
4 5
1 5 1 3
2 1 3
输出样例#1: 复制

2
21

说明

时空限制:1s,128M

数据规模:

对于30%的数据: N≤10,M≤10 N \leq 10, M \leq 10 N≤10,M≤10

对于70%的数据: N≤103,M≤103 N \leq {10}^3, M \leq {10}^3 N≤103,M≤103

对于100%的数据: N≤105,M≤105 N \leq {10}^5, M \leq {10}^5 N≤105,M≤105

其实,纯随机生成的树LCA+暴力是能过的,可是,你觉得可能是纯随机的么233

样例说明:

树的结构如下:

各个操作如下:

故输出应依次为2、21(重要的事情说三遍:记得取模)

解题思路:

  裸的树链剖分的模板。。。

推荐写法:

#include<bits/stdc++.h>
using namespace std;
#define re register int
#define ll long long
#define INF 0x3f3f3f3f
#define maxn 100009
#define maxm
inline ll read()
{
ll x=,f=;char ch=getchar();
while(ch<''||ch>''){if(ch=='-')f=-;ch=getchar();}
while(ch>=''&&ch<=''){x=(x<<)+(x<<)+(ll)(ch-'');ch=getchar();}
return x*f;
}
int id[maxn],rk[maxn],top[maxn],son[maxn],size[maxn],depth[maxn],fa[maxn];
int head[maxn],val[maxn],sum[maxn<<],add[maxn<<];
int n,m,k,ans,tot,cnt,root,base;
struct edge
{
int to,nxt;
}p[maxn<<];
#define ls(x) x<<1
#define rs(x) x<<1|1
void add_edge(re x,re y)
{
p[++cnt]={y,head[x]},head[x]=cnt;
} void dfs1(int u,int father)
{
depth[u]=depth[father]+,fa[u]=father,size[u]=;
for(int i=head[u];i;i=p[i].nxt)
{
int v=p[i].to;
if(v==father) continue;
dfs1(v,u);
size[u]+=size[v];
if(size[v]>size[son[u]])
son[u]=v;
}
} void dfs2(int u,int father)
{
top[u]=father,id[u]=++tot,rk[tot]=u;
if(!son[u]) return ;
dfs2(son[u],father);
for(int i=head[u];i;i=p[i].nxt)
{
int v=p[i].to;
if(v!=son[u]&&v!=fa[u])
dfs2(v,v);
}
} int mod(int x)
{
return x>=base?x%base:x;
} void push_up(int x)
{
sum[x]=sum[ls(x)]+sum[rs(x)];
sum[x]=mod(sum[x]);
} void built(int x,int l,int r)
{
if(l==r)
{
sum[x]=val[rk[l]];
return ;
}
int mid=(l+r)>>;
built(ls(x),l,mid);
built(rs(x),mid+,r);
push_up(x);
} void pass(int x,int l,int r,int k)
{
add[x]+=k,add[x]=mod(add[x]);
sum[x]+=(r-l+)*k,sum[x]=mod(sum[x]);
} void push_down(int x,int l,int r)
{
if(!add[x]) return ;
int mid=(l+r)>>;
pass(ls(x),l,mid,add[x]);
pass(rs(x),mid+,r,add[x]);
add[x]=;
} int Ask(int x,int l,int r,int nl,int nr)
{
int res=;
if(nl<=l&&r<=nr)
return sum[x];
push_down(x,l,r);
int mid=(l+r)>>;
if(nl<=mid)
res+=Ask(ls(x),l,mid,nl,nr),res=mod(res);
if(mid<nr)
res+=Ask(rs(x),mid+,r,nl,nr),res=mod(res);
push_up(x);
return res;
} void Add(int x,int l,int r,int nl,int nr,int k)
{
if(nl<=l&&r<=nr)
{
add[x]+=k,add[x]=mod(add[x]);
sum[x]+=(r-l+)*k,sum[x]=mod(sum[x]);
return ;
}
push_down(x,l,r);
int mid=(l+r)>>;
if(nl<=mid)
Add(ls(x),l,mid,nl,nr,k);
if(mid<nr)
Add(rs(x),mid+,r,nl,nr,k);
push_up(x);
} void Work1(int x,int y,int z)
{
int fx=top[x],fy=top[y];
while(fx!=fy)
{
if(depth[fx]>depth[fy])
swap(x,y),swap(fx,fy);
Add(,,tot,id[fy],id[y],z);
y=fa[fy],fy=top[y];
}
if(id[x]>id[y])
swap(x,y);
Add(,,tot,id[x],id[y],z);
} int Work2(int x,int y)
{
int res=,fx=top[x],fy=top[y];
while(fx!=fy)
{
if(depth[fx]>depth[fy]) swap(x,y),swap(fx,fy);
res+=Ask(,,tot,id[fy],id[y]),res=mod(res);
y=fa[fy],fy=top[y];
}
if(id[x]>id[y]) swap(x,y);
res+=Ask(,,tot,id[x],id[y]),res=mod(res);
} int main()
{
// freopen("1.in","r",stdin);
// freopen("1.out","w",stdout);
n=read(),m=read(),root=read(),base=read();
for(re i=;i<=n;i++)
val[i]=read();
for(re i=;i<n;i++)
{
re x=read(),y=read();
add_edge(x,y),add_edge(y,x);
}
dfs1(root,root),dfs2(root,root);
built(,,tot);
for(re i=;i<=m;i++)
{
re opt=read(),x,y,z;
if(opt==)
{
x=read(),y=read(),z=read();
Work1(x,y,z);
}
if(opt==)
{
x=read(),y=read();
printf("%d\n",Work2(x,y));
}
if(opt==)
{
x=read(),z=read();
Add(,,tot,id[x],id[x]+size[x]-,z);
}
if(opt==)
{
x=read();
printf("%d\n",Ask(,,tot,id[x],id[x]+size[x]-));
}
}
fclose(stdin);
fclose(stdout);
return ;
}
#include<bits/stdc++.h>
using namespace std;
#define re register int
#define ll long long
#define INF 0x3f3f3f3f
#define maxn 100009
#define maxm
#define ls(x) x<<1
#define rs(x) x<<1|1
inline ll read()
{
ll x=,f=;char ch=getchar();
while(ch<''||ch>''){if(ch=='-')f=-;ch=getchar();}
while(ch>=''&&ch<=''){x=(x<<)+(x<<)+(ll)(ch-'');ch=getchar();}
return x*f;
}
ll base;
int n,m,k,ans,tot,cnt,root;
struct edge
{
int to,nxt;
}p[maxn<<];
int head[maxn],id[maxn],fa[maxn],depth[maxn],size[maxn],son[maxn],rk[maxn],top[maxn];
ll sum[maxn<<],add[maxn<<],val[maxn]; void add_edge(int x,int y)
{
p[++cnt].to=y,p[cnt].nxt=head[x],head[x]=cnt;
} void dfs1(int u,int father)
{
depth[u]=depth[father]+,size[u]=,fa[u]=father;
for(int i=head[u];i;i=p[i].nxt)
{
int v=p[i].to;
if(v==father) continue;
dfs1(v,u);
size[u]+=size[v];
if(size[v]>size[son[u]])
son[u]=v;
}
} void dfs2(int u,int father)
{
top[u]=father;
id[u]=++tot;
rk[tot]=u;
if(!son[u])
return ;
dfs2(son[u],father);
for(int i=head[u];i;i=p[i].nxt)
{
int v=p[i].to;
if(v!=son[u]&&v!=fa[u])
dfs2(v,v);
}
} void push_up(int x)
{
sum[x]=(sum[ls(x)]+sum[rs(x)])%base;
} void built(int x,int l,int r)
{
if(l==r)
{
sum[x]=val[rk[l]];
return ;
}
int mid=(l+r)>>;
built(ls(x),l,mid);
built(rs(x),mid+,r);
push_up(x);
} void pass(int x,int l,int r,ll k)
{
add[x]+=k,add[x]%=base;
sum[x]+=(r-l+)*k,sum[x]%=base;
} void push_down(int x,int l,int r)
{
if(!add[x]) return ;
int mid=(l+r)>>;
pass(ls(x),l,mid,add[x]);
pass(rs(x),mid+,r,add[x]);
add[x]=;
} ll Query(int x,int l,int r,int nl,int nr)
{
ll res=;
if(nl<=l&&r<=nr)
return sum[x];
push_down(x,l,r);
int mid=(l+r)>>;
if(nl<=mid)
res+=Query(ls(x),l,mid,nl,nr),res%=base;
if(mid<nr)
res+=Query(rs(x),mid+,r,nl,nr),res%=base;
push_up(x);
return res%base;
} void Add(int x,int l,int r,int nl,int nr,ll k)
{
if(nl<=l&&r<=nr)
{
add[x]+=k,add[x]%=base;
sum[x]+=(r-l+)*k,sum[x]%=base;
return ;
}
push_down(x,l,r);
int mid=(l+r)>>;
if(nl<=mid)
Add(ls(x),l,mid,nl,nr,k);
if(mid<nr)
Add(rs(x),mid+,r,nl,nr,k);
push_up(x);
} void Work1(int x,int y,ll z)
{
int fx=top[x],fy=top[y];
while(fx!=fy)
{
if(depth[fx]>=depth[fy])
{
Add(,,tot,id[fx],id[x],z);
x=fa[fx],fx=top[x];
}
else
{
Add(,,tot,id[fy],id[y],z);
y=fa[fy],fy=top[y];
}
}
if(id[x]<=id[y])
Add(,,tot,id[x],id[y],z);
else
Add(,,tot,id[y],id[x],z);
} ll Work2(int x,int y)
{
ll ans=;
int fx=top[x],fy=top[y];
while(fx!=fy)
{
if(depth[fx]>=depth[fy])
{
ans+=Query(,,tot,id[fx],id[x]);
x=fa[fx];fx=top[x];
}
else
{
ans+=Query(,,tot,id[fy],id[y]);
y=fa[fy];fy=top[y];
}
}
if(id[x]<=id[y])
ans+=Query(,,tot,id[x],id[y]),ans%=base;
else
ans+=Query(,,tot,id[y],id[x]),ans%=base;
return ans%base;
} void Work3(int x,int y)
{
Add(,,tot,id[x],id[x]+size[x]-,y);
} ll Work4(int x)
{
ll res=Query(,,tot,id[x],id[x]+size[x]-);
return res%base;
} int main()
{
freopen("1.in","r",stdin);
freopen("1.out","w",stdout);
n=read(),m=read(),root=read(),base=read();
for(int i=;i<=n;i++)
val[i]=read()%base;
for(int i=;i<n;i++)
{
int x=read(),y=read();
add_edge(x,y),add_edge(y,x);
}
dfs1(root,root),dfs2(root,root);
built(,,tot);
for(int i=;i<=m;i++)
{
int opt=read(),x,y;
ll z;
if(opt==)
{
x=read(),y=read(),z=read();
Work1(x,y,z);
}
if(opt==)
{
x=read(),y=read();
printf("%lld\n",Work2(x,y));
}
if(opt==)
{
x=read(),z=read();
Work3(x,z);
}
if(opt==)
{
x=read();
printf("%lld\n",Work4(x));
}
}
fclose(stdin);
fclose(stdout);
return ;
}

Luogu 3384 【模板】树链剖分的更多相关文章

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

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

  2. luoguP3384 [模板]树链剖分

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

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

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

  4. [洛谷P3384] [模板] 树链剖分

    题目传送门 显然是一道模板题. 然而索引出现了错误,狂wa不止. 感谢神犇Dr_J指正.%%%orz. 建线段树的时候,第44行. 把sum[p]=bv[pos[l]]%mod;打成了sum[p]=b ...

  5. 模板 树链剖分BFS版本

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

  6. 洛谷3384&bzoj1036树链剖分

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

  7. P3384 [模板] 树链剖分

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

  8. 『题解』洛谷P3384 【模板】树链剖分

    Problem Portal Portal1: Luogu Description 如题,已知一棵包含\(N\)个结点的树(连通且无环),每个节点上包含一个数值,需要支持以下操作: 操作\(1\): ...

  9. 树链剖分详解(洛谷模板 P3384)

    洛谷·[模板]树链剖分 写在前面 首先,在学树链剖分之前最好先把 LCA.树形DP.DFS序 这三个知识点学了 emm还有必备的 链式前向星.线段树 也要先学了. 如果这三个知识点没掌握好的话,树链剖 ...

随机推荐

  1. Dynamic Rankings

    板子题 用的整体二分 唯一要注意的是别总手误打错变量 最近总犯这样sb错误,我佛了 #include<bits/stdc++.h> using namespace std; const i ...

  2. 中标麒麟龙芯平台--docker基础镜像制作

    Docker 是一个开源的应用容器引擎,基于 Go 语言 并遵从Apache2.0协议开源.Docker 的出现为开发人员和运维人员带来了极大的便利.Docker在X86下常见的发行版Linux如Ub ...

  3. TypeScript 错误property does not exist on type Object

    TypeScript 错误property does not exist on type Object 在TypeScript中如果按JS的方式去获取对象属性,有时会提示形如Property 'val ...

  4. Jquery笔记和ajax笔记

    Jquery笔记:jQuery是一个JavaScript函数库,专为事件处理设计 1.jQuery的引入 <script text="type/javascript" src ...

  5. json中的json.dumps()

    Json简介 JSON(JavaScript Object Notation) 是一种轻量级的数据交换格式.它基于JavaScript(Standard ECMA-262 3rd Edition - ...

  6. Elastichsearch实践——基本使用

    官网文档:https://www.elastic.co/guide/cn/elasticsearch/guide/current/getting-started.html es中的索引.类型.文档可以 ...

  7. JavaScript 当月第一天和最后一天

    1. 概述 1.1 说明 在项目过程中,有时候需要默认展示一个月的查询条件,即当月的第一天和最后一天. 2. 代码 2.1 代码示例 直接调用getFirstAndLastDay()即可得到当月的第一 ...

  8. idea的一些设置

    在File->Settings->Appearance & Behavior->System Settings->Updates下取消Automatically che ...

  9. Unity iOS Appstore 上架的问题

    之前一直是一个人的名义上架的应用.现在变成:公司的账号就会出现一些莫名的问题: 首先是账号需要新的boulder名字,新建之后下载验证key. 注意:真机测试不发布,选择自动签名就行了:需要发布就取消 ...

  10. 处理 oracle 数据库导入报错“IMP-00058: 遇到 ORACLE 错误 942”

    在导入数据文件的时候出现了下图错误: 经过多次百度搜索问题.得知问题错误方向: 仔细的查询了被导入数据的数据库的版本: 而 被导入的数据包 dmp 文件是从 oracle11g r2的版本导出的. 所 ...