题目描述

如题,已知一棵包含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

对于70%的数据:N<=1000,M<=1000

对于100%的数据:N<=100000,M<=100000

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

样例说明:

树的结构如下:

各个操作如下:

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

---------------------------------------x_x--------------------------------------

就是树链剖分

终于可以超熟练的在半小时内搞出树链剖分 好开心

代码如下:

#include<cstdio>
#include<cstring>
#include<iostream>
#define N 150000
#define For(i,x,y) for(int i=x;i<=y;++i)
using namespace std;
typedef long long LL;
int n,m,r,M;
struct Tree{
#define lson(x) (x<<1)
#define rson(x) ((x<<1)+1)
LL l[N*],r[N*],w[N*],sum[N*];
void upd(int x){sum[x]=(sum[lson(x)]+sum[rson(x)]+w[x]*(r[x]-l[x]+))%M;}
void build(int p,int L,int R)
{
l[p]=L;r[p]=R;w[p]=;
if(L==R)return;
int MID=(L+R)>>;
build(lson(p),L,MID);
build(rson(p),MID+,R);
}
void ins(int p,int x,int v)
{
int L=l[p],R=r[p];int MID=(L+R)>>;
if(L==R){
w[p]+=v;w[p]%=M;upd(p);return;
}
if(x<=MID)ins(lson(p),x,v);
else ins(rson(p),x,v);
upd(p);
}
void add(int x,int L,int R,int v)
{
int mid=(l[x]+r[x])>>;
if(l[x]==L&&r[x]==R)
{
w[x]+=v;w[x]%=M;upd(x);return;
}
if(R<=mid)add(lson(x),L,R,v);
if(L>mid)add(rson(x),L,R,v);
if(R>mid&&L<=mid)
{
add(lson(x),L,mid,v);
add(rson(x),mid+,R,v);
}
upd(x);
}
int getsum(int x,int L,int R)
{
int mid=(l[x]+r[x])>>;int tans=w[x]*(R-L+)%M;
if(l[x]==L&&r[x]==R)
{
return sum[x];
}
if(R<=mid)return (getsum(lson(x),L,R)+tans)%M;
if(L>mid)return (getsum(rson(x),L,R)+tans)%M;
if(R>mid&&L<=mid)
{
return (getsum(lson(x),L,mid)+getsum(rson(x),mid+,R)+tans)%M;
}
}
}T;
struct Graph{
struct E{
int next,to;
}edge[N*];
int head[N];int cnt;
bool vis[N];LL v[N],size[N],son[N],top[N],id[N],deep[N],fa[N],xid[N];
int sign;
void adde(int u,int v)
{
edge[++cnt].to=v;edge[cnt].next=head[u];head[u]=cnt;
edge[++cnt].to=u;edge[cnt].next=head[v];head[v]=cnt;
} void dfs1(int u)
{
size[u]=;int S=;
for(int i=head[u];i;i=edge[i].next)
{
int v=edge[i].to;
if(vis[v])continue;vis[v]=;
deep[v]=deep[u]+;fa[v]=u;
dfs1(v);
size[u]+=size[v];
if(!S||size[v]>size[S])S=v;
}
son[u]=S;
}
void dfs2(int u,int tp)
{
id[u]=++sign;
top[u]=tp;
if(!son[u]){xid[u]=sign;return;}
vis[son[u]]=;
dfs2(son[u],tp);
for(int i=head[u];i;i=edge[i].next)
{
int v=edge[i].to;if(vis[v])continue;
vis[v]=;dfs2(v,v);
}
xid[u]=sign;
}
void prework()
{
cin>>n>>m>>r>>M;
For(i,,n)scanf("%d",&v[i]);
For(i,,n-)
{
int u,v;scanf("%d%d",&u,&v);
adde(u,v);
}
vis[r]=;
dfs1(r);
memset(vis,,sizeof(vis));
vis[r]=;
dfs2(r,r);
T.build(,,n);
For(i,,n)T.ins(,id[i],v[i]);
}
void add1(int u,int v,int w)
{
if(deep[top[u]]<deep[top[v]])swap(u,v);
while(top[u]!=top[v])
{
T.add(,id[top[u]],id[u],w);
u=fa[top[u]];
if(deep[top[u]]<deep[top[v]])swap(u,v);
}
if(deep[u]<deep[v])swap(u,v);
T.add(,id[v],id[u],w);
}
int get(int u,int v)
{
int ans=;
if(deep[top[u]]<deep[top[v]])swap(u,v);
while(top[u]!=top[v])
{
ans=(ans+T.getsum(,id[top[u]],id[u]))%M;
u=fa[top[u]];
if(deep[top[u]]<deep[top[v]])swap(u,v);
}
if(deep[u]<deep[v])swap(u,v);
ans=(ans+T.getsum(,id[v],id[u]))%M;
return ans%M;
}
void add2(int u,int w)
{
T.add(,id[u],xid[u],w);
}
int get2(int u)
{
return T.getsum(,id[u],xid[u])%M;
}
}G;
int main()
{
G.prework();
For(t,,m)
{
int opt;
scanf("%d",&opt);
int u,v,w;
if(opt==)
{
scanf("%d%d%d",&u,&v,&w);
G.add1(u,v,w);
}
if(opt==)
{
scanf("%d%d",&u,&v);printf("%d\n",G.get(u,v));
}
if(opt==)
{
scanf("%d%d",&u,&w);G.add2(u,w);
}
if(opt==)
{
scanf("%d",&u);printf("%d\n",G.get2(u));
}
}
}

P.S.有没有觉得我的代码超帅啊 结构体凶在那里 @sjj118

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

  1. 洛谷P3384 树链剖分

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

  2. 洛谷 P3384树链剖分 题解

    题面 挺好的一道树剖模板: 首先要学会最模板的树剖: 然后这道题要注意几个细节: 初始化时,seg[0]=1,seg[root]=1,top[root]=root,rev[1]=root; 在线段树上 ...

  3. 洛谷 [P3384] 树链剖分 模版

    支持各种数据结构上树,注意取膜. #include <iostream> #include <cstring> #include <algorithm> #incl ...

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

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

  5. 【算法学习】【洛谷】树链剖分 & P3384 【模板】树链剖分 P2146 软件包管理器

    刚学的好玩算法,AC2题,非常开心. 其实很早就有教过,以前以为很难就没有学,现在发现其实很简单也很有用. 更重要的是我很好调试,两题都是几乎一遍过的. 介绍树链剖分前,先确保已经学会以下基本技巧: ...

  6. 洛谷 P2146 [NOI2015]软件包管理器 (树链剖分模板题)

    题目描述 Linux用户和OSX用户一定对软件包管理器不会陌生.通过软件包管理器,你可以通过一行命令安装某一个软件包,然后软件包管理器会帮助你从软件源下载软件包,同时自动解决所有的依赖(即下载安装这个 ...

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

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

  8. 【树链剖分】洛谷P3379 树链剖分求LCA

    题目描述 如题,给定一棵有根多叉树,请求出指定两个点直接最近的公共祖先. 输入输出格式 输入格式: 第一行包含三个正整数N.M.S,分别表示树的结点个数.询问的个数和树根结点的序号. 接下来N-1行每 ...

  9. BZOJ 1036 树的统计Count 树链剖分模板题

    题目链接: https://www.lydsy.com/JudgeOnline/problem.php?id=1036 题目大意: 一棵树上有n个节点,编号分别为1到n,每个节点都有一个权值w.我们将 ...

随机推荐

  1. js图片放大效果

    实现购物网站里的图片放大效果,jqzoom很好用.今天才接触它,很快就上手了.看了一个示例,在放大图像上方貌似有水印,后经排查,原来是图片的标题,然后设置title为false,搞定.

  2. convertdate

    sample date 2015-09-10 00:00:00 2015-09-09 00:00:00.000 expect iso date, add time zone 2015-09-10T00 ...

  3. 【转】Matlab练习程序(各向异性扩散)

    http://www.cnblogs.com/tiandsp/archive/2013/04/18/3029468.html 主要是用来平滑图像的,克服了高斯模糊的缺陷,各向异性扩散在平滑图像时是保留 ...

  4. SQLServer - 约束

    一.约束的分类 在SQLServer中,有3种不同类型的约束. 1.实体约束 实体约束是关于行的,比如某一行出现的值就不允许出现在其他行,例如主键. 2.域约束 域约束是关于列的,对于所有行,某一列有 ...

  5. javaSE学习路线

    Java SE大致可分为以下几块内容: n  对象导论:如何用面向对象的思路来开发 n  深入JVM:Java运行机制以及JVM原理 n  面向对象的特征:封装.继承.抽象.多态 n  数组和容器:容 ...

  6. SparkSQL读取Hive中的数据

    由于我Spark采用的是Cloudera公司的CDH,并且安装的时候是在线自动安装和部署的集群.最近在学习SparkSQL,看到SparkSQL on HIVE.下面主要是介绍一下如何通过SparkS ...

  7. PHP 单引号 与双引号区别

    在PHP中,字符串的定义可以使用单引号,也可以使用双引号. PHP允许我们在双引号串中直接包含字串变量,双引号串中的变量将被解释而且替换,而单引号串中的内容总被认为是普通字符.例如: $foo = 2 ...

  8. 自己动手做logo

    本文主要记录用 coreDraw 和ps 做公司logo . 我修改的logo.效果还不错. 1 矢量图 和位图的区别 http://jingyan.baidu.com/article/54b6b9c ...

  9. (l老陈-小石头)典型用户、用户故事、用例图

    一.典型用户 老陈 小石头 二.用户故事 老陈:作为一个家长,我希望能利用软件在电脑上储存一些数学题目,以便在繁忙的工作中也能帮助到孩子提高数学. 小石头:作为一个小学二年级的小学生,我希望能利用软件 ...

  10. SQL Server简单语句/待整理

    数据库对象:表Table,视图View,存储过程Stored Procedure,触发器Trigger 关系:1关系=1二维表,1关系有1关系名.1关系=1表对象 属性/字段: 二维表中垂直方向的列 ...