[luogu P3384] 【模板】树链剖分 [树链剖分]
题目描述
如题,已知一棵包含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取模)
输入输出样例
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
2
21
说明
时空限制:1s,128M
数据规模:
对于30%的数据:N<=10,M<=10
对于70%的数据:N<=1000,M<=1000
对于100%的数据:N<=100000,M<=100000
(其实,纯随机生成的树LCA+暴力是能过的,可是,你觉得可能是纯随机的么233)
样例说明:
树的结构如下:
各个操作如下:
故输出应依次为2、21(重要的事情说三遍:记得取模)
My Solution
哪来的什么solution
因为这题快颓了week了
统计:2/29 AC!!!
为什么我之前要用树状数组嘞
向unsigned大佬低头 orz
#include<cstdio>
#include<iostream>
#include<cstring>
using namespace std; typedef long long ll; inline int read(){
char ch;
int re=;
bool flag=;
while((ch=getchar())!='-'&&(ch<''||ch>''));
ch=='-'?flag=:re=ch-'';
while((ch=getchar())>=''&&ch<='') re=re*+ch-'';
return flag?-re:re;
} inline ll rea(){
char ch;
ll re=;
bool flag=;
while((ch=getchar())!='-'&&(ch<''||ch>''));
ch=='-'?flag=:re=ch-'';
while((ch=getchar())>=''&&ch<='') re=re*+ch-'';
return flag?-re:re;
} struct edge{
int to,next;
edge(int to=,int next=):
to(to),next(next){}
}; struct Segment_Tree{
int l,r;
ll sum,tag;
}; const int maxn=; int cnt,n,m,root;
ll mod;
edge edges[maxn<<];
Segment_Tree tre[maxn<<];
int head[maxn],top[maxn],dep[maxn],fat[maxn],id[maxn],id_[maxn],son[maxn],siz[maxn];
int data[maxn]; inline void add_edge(int from,int to){
edges[++cnt]=edge(to,head[from]); head[from]=cnt;
edges[++cnt]=edge(from,head[to]); head[to]=cnt;
} void init(){
n=read(); m=read(); root=read(); mod=rea();
for(int i=;i<=n;i++)
data[i]=read();
int from,to;
cnt=;
for(int i=;i<n;i++){
from=read(); to=read();
add_edge(from,to);
}
} void dfs_1(int x,int fa){
fat[x]=fa;
siz[x]=;
dep[x]=dep[fa]+;
for(int ee=head[x];ee;ee=edges[ee].next)
if(edges[ee].to!=fa){
dfs_1(edges[ee].to,x);
siz[x]+=siz[edges[ee].to];
if(!son[x]||siz[edges[ee].to]>siz[son[x]])
son[x]=edges[ee].to;
}
} void dfs_2(int x,int fa){
if(!son[x]) return;
top[son[x]]=top[x];
id[son[x]]=++cnt;
id_[cnt]=son[x];
dfs_2(son[x],x);
for(int ee=head[x];ee;ee=edges[ee].next)
if(edges[ee].to!=fa&&edges[ee].to!=son[x]){
top[edges[ee].to]=edges[ee].to;
id[edges[ee].to]=++cnt;
id_[cnt]=edges[ee].to;
dfs_2(edges[ee].to,x);
}
} inline void push_up(int x){
tre[x].sum=tre[x<<].sum+tre[x<<|].sum;
} inline void push_down(int x){
tre[x<<].tag+=tre[x].tag;
tre[x<<].sum+=tre[x].tag*(tre[x<<].r-tre[x<<].l+);
tre[x<<|].tag+=tre[x].tag;
tre[x<<|].sum+=tre[x].tag*(tre[x<<|].r-tre[x<<|].l+);
tre[x].tag=;
return;
} void build(int x,int l,int r){
tre[x].l=l; tre[x].r=r;
if(l==r){
tre[x].sum=data[id_[l]];
return;
}
int mid=(l+r)>>;
build(x<<,l,mid);
build(x<<|,mid+,r);
push_up(x);
} void make(){
dfs_1(root,);
cnt=;
top[root]=root;
id[root]=cnt;
id_[cnt]=root;
dfs_2(root,);
build(,,n);
} void update(int x,int L,int R,ll c){
if(L<=tre[x].l&&tre[x].r<=R){
tre[x].tag+=c;
tre[x].sum+=c*(tre[x].r-tre[x].l+);
return;
}
push_down(x);
int mid=(tre[x].l+tre[x].r)>>;
if(R<=mid) update(x<<,L,R,c);
else if(L>mid) update(x<<|,L,R,c);
else{
update(x<<,L,mid,c);
update(x<<|,mid+,R,c);
}
push_up(x);
} ll query_sum(int x,int L,int R){
if(L<=tre[x].l&&tre[x].r<=R)
return tre[x].sum;
push_down(x);
int mid=(tre[x].l+tre[x].r)>>;
if(R<=mid) return query_sum(x<<,L,R);
else if(L>mid) return query_sum(x<<|,L,R);
else return query_sum(x<<,L,mid)+query_sum(x<<|,mid+,R);
} void change(int u,int v,ll c){
int f1=top[u];
int f2=top[v];
while(f1!=f2){
// this ensure u and v is not at the same heavy chain
if(dep[f1] < dep[f2]){
// ensure that heavy chain 1 is under heavy chain 2
swap(f1,f2);
swap(u,v);
}
update(,id[f1],id[u],c);
u=fat[f1];
f1=top[u];
}
if(dep[u]>dep[v]) swap(u, v);
update(,id[u],id[v],c);
} ll find_sum(int u, int v)
{
ll sum=;
int f1=top[u];
int f2=top[v];
while(f1!=f2)
{
if(dep[f1]<dep[f2])
{
swap(f1,f2);
swap(u,v);
}
sum+=query_sum(,id[f1],id[u]);
sum%=mod;
u=fat[f1];
f1=top[u];
}
if(dep[u]>dep[v]) swap(u, v);
sum+=query_sum(,id[u],id[v]);
return sum%mod;
} void solve(){
int opt,ss,tt;
ll c;
for(int i=;i<m;i++){
opt=read();
if(opt&){
//opt==3
if(opt&){
ss=read(); c=rea();
update(,id[ss],id[ss]+siz[ss]-,c);
}
//opt==1
else{
ss=read(); tt=read(); c=rea();
change(ss,tt,c);
}
}
else{
//opt==4
if(opt&){
ss=read();
printf("%lld\n",query_sum(,id[ss],id[ss]+siz[ss]-)%mod);
}
//opt==2
else{
ss=read(); tt=read();
printf("%lld\n",find_sum(ss,tt));
}
}
}
} int main(){
//freopen("data.in","r",stdin);
init();
make();
solve();
return ;
}
爱你锋利的伤痕 爱你成熟的天真
[luogu P3384] 【模板】树链剖分 [树链剖分]的更多相关文章
- [luogu P3384] [模板]树链剖分
[luogu P3384] [模板]树链剖分 题目描述 如题,已知一棵包含N个结点的树(连通且无环),每个节点上包含一个数值,需要支持以下操作: 操作1: 格式: 1 x y z 表示将树从x到y结点 ...
- 【模板】树链剖分(Luogu P3384)
题目描述 众所周知 树链剖分是个好东西QWQ 也是一个代码量破百的算法 基本定义 树路径信息维护算法. 将一棵树划分成若干条链,用数据结构去维护每条链,复杂度为O(logN). 其实本质是一些数据结 ...
- 洛谷 P3384 【模板】树链剖分-树链剖分(点权)(路径节点更新、路径求和、子树节点更新、子树求和)模板-备注结合一下以前写的题目,懒得写很详细的注释
P3384 [模板]树链剖分 题目描述 如题,已知一棵包含N个结点的树(连通且无环),每个节点上包含一个数值,需要支持以下操作: 操作1: 格式: 1 x y z 表示将树从x到y结点最短路径上所有节 ...
- 【Luogu】P3950部落冲突(树链剖分)
题目链接 状态奇差无比,sbt都能错一遍. 不动笔光想没有想到怎么做,画图之后发现一个很明显的性质…… 那就是两个开战的部落,其中一个是另一个的父亲. 所以在儿子那里加个权值.查询的时候树链剖分查询链 ...
- Aragorn's Story 树链剖分+线段树 && 树链剖分+树状数组
Aragorn's Story 来源:http://www.fjutacm.com/Problem.jsp?pid=2710来源:http://acm.hdu.edu.cn/showproblem.p ...
- hdu 3966 Aragorn's Story(树链剖分+树状数组/线段树)
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=3966 题意: 给出一棵树,并给定各个点权的值,然后有3种操作: I C1 C2 K: 把C1与C2的路 ...
- BZOJ_3589_动态树_容斥原理+树链剖分
BZOJ_3589_动态树_容斥原理+树链剖分 题意: 维护一棵树,支持1.子树内点权加上一个数 2.给出k条链,求路径上的点权和(重复的计算一次) (k<=5) 分析: 可以用树剖+线段树解 ...
- dfs序+主席树 或者 树链剖分+主席树(没写) 或者 线段树套线段树 或者 线段树套splay 或者 线段树套树状数组 bzoj 4448
4448: [Scoi2015]情报传递 Time Limit: 20 Sec Memory Limit: 256 MBSubmit: 588 Solved: 308[Submit][Status ...
- dsu+树链剖分+树分治
dsu,对于无修改子树信息查询,并且操作支持undo的问题 暴力dfs,对于每个节点,对所有轻儿子dfs下去,然后再消除轻儿子的影响 dfs重儿子,然后dfs暴力恢复轻儿子们的影响,再把当前节点影响算 ...
- 2016湖南省赛 I Tree Intersection(线段树合并,树链剖分)
2016湖南省赛 I Tree Intersection(线段树合并,树链剖分) 传送门:https://ac.nowcoder.com/acm/contest/1112/I 题意: 给你一个n个结点 ...
随机推荐
- 在附件管理模块中增加对FTP 上传和预览的支持
在之前介绍的附件管理模块里面<Winform开发框架之通用附件管理模块>以及<Winform开发框架之附件管理应用>,介绍了附件的管理功能,通过对数据库记录的处理和文件的管理, ...
- Go从入门到精通(一)go语言初始
一.第一个go程序 package main import ( "fmt" ) func main(){ fmt.Println("hello world") ...
- 实验:Oracle数据泵导出导入之序列问题
今天同事提出了一个问题: 使用数据泵expdp导出1个schema,有个表主键是触发器自增的id,导入测试库测试时,发现表里的数据比自增序列的值要大.导致插入数据报错. 最终结论是: 由于数据库先进行 ...
- 多线程异步编程示例和实践-Task
上篇博文中,我们介绍了Thread和ThreadPool: 多线程异步编程示例和实践-Thread和ThreadPool 本文中我们继续,说一下TPL(Task Parallel Library, 简 ...
- 搭建rtmp直播流服务之4:videojs和ckPlayer开源播放器二次开发(播放rtmp、hls直播流及普通视频)
前面几章讲解了使用 nginx-rtmp搭建直播流媒体服务器; ffmpeg推流到nginx-rtmp服务器; java通过命令行调用ffmpeg实现推流服务; 从数据源获取,到使用ffmpeg推流, ...
- Spring学习(11)---JSR-250标准注解之 @Resource、@PostConstruct、@PreDestroy
1)@Resource(JSR-250标准注解,推荐使用它来代替Spring专有的@Autowired注解) Spring 不但支持自己定义的@Autowired注解,还支持几个由JSR-250规范定 ...
- 原型----------prototype详细解答
function ren(name,age){ this.name=name; this.age=age; this.fa=function(){ alert('我喜欢吃'); } } var p1= ...
- ArcGIS Earth(原谷歌地球)如何获取高精度矢量地图数据?(shp文件/要素类/kml)
大家好,这次来分享干货.做地理分析的同学,或者需要使用地图却不知道哪里有矢量数据的时候,怎么办呢? 这次,我就告诉大家哪里能自己手工制作矢量点线面数据!注意哦,是自己绘制的. 使用到的软件: ArcG ...
- 集成python双版本详解
最近要准备学习Python,由于版本上的差异,不知道要学哪个,现在好多东西都是基于python2基础的,但是python2在2020年左右就可能停止了,所以干脆决定两个都装上吧! 首先上官网上下载 ...
- nginx+ftp搭建图片服务器(Windows Server服务器环境下)
几种图片服务器的对比 1.直接使用ftp服务器,访问图片路径为 ftp://账户:密码@192.168.0.106/31275-105.jpg 不采用这种方式,不安全容易暴露ftp账户信息 2.直接使 ...