洛谷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≤10^3,M≤10^3
对于100%的数据: N≤10^5,M≤10^5
( 其实,纯随机生成的树LCA+暴力是能过的,可是,你觉得可能是纯随机的么233 )
样例说明:
树的结构如下:
各个操作如下:
故输出应依次为2、21(重要的事情说三遍:记得取模)
#include<cmath>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#define maxn 100007
using namespace std;
long long read()
{
long long x=,f=;
char ch=getchar();
while(ch<''||ch>'')
{
if(ch=='-')
f=-;
ch=getchar();
}
while(ch>=''&&ch<='')
{
x=x*+ch-'';
ch=getchar();
}
return x*f;
}
int n,m,num,root,p,opt,x,y,z,cnt;
int head[maxn*],a[maxn],son[maxn],fa[maxn],deep[maxn],size[maxn],top[maxn],pos[maxn],data[maxn],in[maxn],out[maxn];
struct node
{
int v,nxt;
} e[maxn];
void add(int u,int v)
{
e[++num].v=v;
e[num].nxt=head[u];
head[u]=num;
e[++num].v=u;
e[num].nxt=head[v];
head[v]=num;
}
struct NODE
{
int l,r,sum,flag;
} tree[maxn*];
void dfs(int now)
{
size[now]=;
for(int i=head[now]; i; i=e[i].nxt)
if(fa[now]!=e[i].v)
{
fa[e[i].v]=now;
deep[e[i].v]=deep[now] + ;
dfs(e[i].v);
size[now]+=size[e[i].v];
if(size[son[now]]<size[e[i].v])
son[now]=e[i].v;
}
}
void DFS(int now,int num)
{
top[now]=num;
pos[now]=++cnt;
in[now]=cnt;
data[cnt]=a[now];
if(son[now])
DFS(son[now],num);
for(int i=head[now]; i; i=e[i].nxt)
if(fa[now]!=e[i].v&&e[i].v!=son[now])
DFS(e[i].v,e[i].v);
out[now]=cnt;
}
void build(int now,int l,int r)
{
tree[now].l=l;
tree[now].r=r;
tree[now].flag=;
if(l==r)
{
tree[now].sum=data[l];
return ;
}
int mid=(l+r)>>;
build(now<<,l,mid);
build(now<<|,mid+,r);
tree[now].sum=tree[now<<].sum+tree[now<<|].sum;
}
void down(int now)
{
if(tree[now].l==tree[now].r)
{
tree[now].flag=;
return ;
}
tree[now<<].flag+=tree[now].flag;
tree[now<<|].flag+=tree[now].flag;
tree[now<<].sum=(tree[now<<].sum+tree[now].flag*(tree[now<<].r-tree[now<<].l+))%p;
tree[now<<|].sum=(tree[now<<|].sum+tree[now].flag*(tree[now<<|].r-tree[now<<|].l+))%p;
tree[now].flag=;
}
void change(int now,int l,int r,int f)
{
while(tree[now].flag)
down(now);
if(tree[now].l>r||tree[now].r<l)
return ;
if(tree[now].l>=l&&tree[now].r<=r)
{
tree[now].flag=f;
(tree[now].sum+=f*(tree[now].r-tree[now].l+))%=p;
return ;
}
change(now<<,l,r,f);
change(now<<|,l,r,f);
tree[now].sum=(tree[now<<].sum+tree[now<<|].sum)%p;
}
int query(int now,int l,int r)
{
while(tree[now].flag) down(now);
if(tree[now].l>r||tree[now].r<l)
return ;
if(tree[now].l>=l&&tree[now].r<=r)
return tree[now].sum;
return (query(now<<,l,r)+query(now<<|,l,r))%p;
}
void add1()
{
x=read(),y=read(),z=read(),z%=p;
while(top[x]!=top[y])
{
if(deep[top[x]]<deep[top[y]])
swap(x,y);
change(,pos[top[x]],pos[x],z);
x=fa[top[x]];
}
if(deep[x]<deep[y])
swap(x,y);
change(,pos[y],pos[x],z);
}
void add2()
{
x=read(),z=read(),z%=p;
change(,in[x],out[x],z);
}
void query1()
{
x=read(),y=read();
int ans=;
while(top[x]!=top[y])
{
if(deep[top[x]]<deep[top[y]])
swap(x,y);
ans=(ans+query(,pos[top[x]],pos[x]))%p;
x=fa[top[x]];
}
if(deep[x]<deep[y])
swap(x,y);
(ans+=query(,pos[y],pos[x]))%=p;
printf("%d\n",ans);
}
void query2()
{
x=read();
int ans=;
(ans=query(,in[x],out[x]))%=p;
printf("%d\n",ans);
}
int main()
{
n=read(),m=read(),root=read(),p=read();
for(int i=; i<=n; ++i)
a[i]=read(),a[i]%=p;
for(int i=,a,b; i<n; ++i)
a=read(),b=read(),add(a,b);
dfs(root);
DFS(root,root);
build(,,n);
while(m--)
{
opt=read();
if(opt==)
add1();
else if(opt==)
add2();
else if(opt==)
query1();
else
query2();
}
return ;
}
洛谷P3384 【模板】树链剖分的更多相关文章
- [洛谷P3384] [模板] 树链剖分
题目传送门 显然是一道模板题. 然而索引出现了错误,狂wa不止. 感谢神犇Dr_J指正.%%%orz. 建线段树的时候,第44行. 把sum[p]=bv[pos[l]]%mod;打成了sum[p]=b ...
- [luogu P3384] [模板]树链剖分
[luogu P3384] [模板]树链剖分 题目描述 如题,已知一棵包含N个结点的树(连通且无环),每个节点上包含一个数值,需要支持以下操作: 操作1: 格式: 1 x y z 表示将树从x到y结点 ...
- 洛谷P3979 遥远的国度 树链剖分+分类讨论
题意:给出一棵树,这棵树每个点有权值,然后有3种操作.操作一:修改树根为rt,操作二:修改u到v路径上点权值为w,操作三:询问以rt为根x子树的最小权值. 解法:如果没有修改树根操作那么这题就是树链剖 ...
- 洛谷 P4114 Qtree1 树链剖分
目录 题面 题目链接 题目描述 输入输出格式 输入格式: 输出格式: 输入输出样例 输入样例: 输出样例: 说明 说明 思路 Change Query AC代码 总结 题面 题目链接 P4114 Qt ...
- 洛谷.4114.Qtree1(树链剖分)
题目链接 模板题都错了这么多次.. //边权赋到点上 树剖模板 //注意LCA.链的顶端不能统计到答案! #include <cstdio> #include <cctype> ...
- 洛谷3384&bzoj1036树链剖分
值得注意的是: 一个点的子树是存在一起的...也就是说我们修改子树的时候只用... /********************************************************* ...
- P3384 [模板] 树链剖分
#include <bits/stdc++.h> using namespace std; typedef long long ll; int n, m, rt, mod, cnt, to ...
- luoguP3384 [模板]树链剖分
luogu P3384 [模板]树链剖分 题目 #include<iostream> #include<cstdlib> #include<cstdio> #inc ...
- 【Luogu P3384】树链剖分模板
树链剖分的基本思想是把一棵树剖分成若干条链,再利用线段树等数据结构维护相关数据,可以非常暴力优雅地解决很多问题. 树链剖分中的几个基本概念: 重儿子:对于当前节点的所有儿子中,子树大小最大的一个儿子就 ...
- 模板 树链剖分BFS版本
//点和线段树都从1开始 //边使用vector vector<int> G[maxn]; ],num[maxn],iii[maxn],b[maxn],a[maxn],top[maxn], ...
随机推荐
- Javascript 面向对象的编程思想
面向对象,首先得有类的概念,没有类造不出来对象,,Javascript把函数名看成类. 其次分为不同结构层,如三层架构.MVC.MVVM. 本文根据实际项目演练,分为几个适用的结构层,如果项目不大一般 ...
- 学习ReentrantLock
1. 使用ReentrantLock import java.util.concurrent.locks.ReentrantLock; public class TestReentrantLock { ...
- 每天一个linux命令(12):more命令
1.命令简介 more (more) 该命令一次显示一屏文本,满屏后停下来,并且在屏幕的底部出现一个提示信息,给出至今己显示的该文件的百分比,方便逐页阅读(file perusal filter fo ...
- CMD 命令1
cmd /c dir 是执行完dir命令后关闭命令窗口. cmd /k dir 是执行完dir命令后不关闭命令窗口. cmd /c start dir 会打开一个新窗口后执行dir指令,原窗口会关闭. ...
- 浅谈 CSS 预处理器: 为什么要使用预处理器?
CSS 自诞生以来,基本语法和核心机制一直没有本质上的变化,它的发展几乎全是表现力层面上的提升.最开始 CSS 在网页中的作用只是辅助性的装饰,轻便易学是最大的需求:然而如今网站的复杂度已经不可同日而 ...
- Docker的学习
学习地址:http://blog.51cto.com/lizhenliang 和 他的视频 一 Docker 的介绍和安装 二 镜像管理 三 容器管理 四 管理应用程序数据 五 使用Docker知 ...
- Python中的高级数据结构详解
这篇文章主要介绍了Python中的高级数据结构详解,本文讲解了Collection.Array.Heapq.Bisect.Weakref.Copy以及Pprint这些数据结构的用法,需要的朋友可以参考 ...
- Linux Performance tool
https://www.tecmint.com/command-line-tools-to-monitor-linux-performance/ https://www.tecmint.com/lin ...
- 配置Windows 2008 R2 防火墙允许远程访问SQL Server 2008 R2
1.先修改 sql server 2008R2的端口号吧,1433经常成为别人入侵的端口,在sql server 配置管理器 -->sql server 网络配置-->MSSQLSERVE ...
- RTT(往返时间)和RPC
RTT(Round-Trip Time)往返时间在计算机网络中它是一个重要的性能指标.表示从发送端发送数据开始,到发送端收到来自接收端的确认(接收端收到数据后便立即发送确认,不包含数据传输时间)总共经 ...