[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个结点 ...
随机推荐
- C#程序遍历数组A中所有元素
] { "a1","a2","a3","a4","a5"}; //第一种方法 ; i < A. ...
- blog界面自己写了css,参考了网站设计,想要的自己拿
junhey这就把界面的代码公布下来,可以自己修改额~(ps:麻烦加个友链http://www.cnblogs.com/junhey/ 谢谢) /* 初始化样式 */ html, body, div, ...
- java原生实现屏幕设备遍历和屏幕采集(捕获)等功能
前言:本章中屏幕捕获使用原生java实现,屏幕图像显示采用javacv1.3的CanvasFrame 一.实现的功能 1.屏幕设备遍历 2.本地屏幕图像采集(也叫屏幕图像捕获) 3.播放本地图像(采用 ...
- Oracle数据库和客户端字符集
1.查看数据库字符集信息 SQL> select * from nls_database_parameters;其中,NLS_CHARACTERSET是当前数据库的字符集. 2.客户端字符集 客 ...
- 深入理解JavaScript中的闭包
闭包没有想象的那么简单 闭包的概念在JavaScript中占据了十分重要的地位,有不少开发者分不清匿名函数和闭包的概念,把它们混为一谈,我希望借这篇文章能够让大家对闭包有一个清晰的认识. 大家都知道变 ...
- node.js零基础详细教程(7):node.js操作mongodb,及操作方法的封装
第七章 建议学习时间4小时 课程共10章 学习方式:详细阅读,并手动实现相关代码 学习目标:此教程将教会大家 安装Node.搭建服务器.express.mysql.mongodb.编写后台业务逻辑. ...
- ubuntu16.04-x64系统中Jexus web server部署.NetCore和端口分析引发的猜想!
您有这样的牢骚么? 有一周没更新博客了,简单说下在干什么吧:主要是公司安排对接某旅游大公司的接口,接口数量倒也就10个左右,对接完后还需要加入到业务系统中和App端,因此还是需要花点时间的:时间上来说 ...
- pythonic-让python代码更高效
何为pythonic? pythonic如果翻译成中文的话就是很python.很+名词结构的用法在中国不少,比如:很娘,很国足,很CCTV等等. 我的理解为,很+名词表达了一种特殊和强调的意味.所以很 ...
- test_CSDN_markdown_format
test Markdown编辑器写博客,使用CSDN的markdown模版 测试结果 不支持的模块 生成目录[toc] 流程图 文献引用 其它模块正常 正文 本Markdown编辑器使用StackEd ...
- Hbase FilterList使用总结
作者:Syn良子 出处:http://www.cnblogs.com/cssdongl/p/7098138.html 转载请注明出处 我们知道Hbase的Scan经常需要用到filter来过滤表中的数 ...