洛谷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], ...
随机推荐
- 自建证书配置HTTPS服务器
1.写这篇博客的初衷是因为最近iOS9出来了,苹果官方默认要求使用HTTPS,所以自己想整一个HTTPS服务器,也想好好了解一下HTTPS通信,也知道了HTTPS其实就是在HTTP的基础上加上了SSL ...
- 构建自己的 Smart Life 私有云(一)-> 破解涂鸦智能插座
博客搬迁至https://blog.wangjiegulu.com RSS订阅:https://blog.wangjiegulu.com/feed.xml 原文链接:https://blog.wang ...
- linux内核剖析(十一)进程间通信之-共享内存Shared Memory
共享内存 共享内存是进程间通信中最简单的方式之一. 共享内存是系统出于多个进程之间通讯的考虑,而预留的的一块内存区. 共享内存允许两个或更多进程访问同一块内存,就如同 malloc() 函数向不同进程 ...
- Centos7.4 安装Docker
一.安装docker yum install -y docker 二.启动docker服务 systemctl start docker 三.设置成开机启动docker服务 systemctl ena ...
- maven手动安装本地jar到仓库
1.有时候IDE maven下载不到jar,这时候可以在官网下载对应jar后安装到maven仓库. 下面以jdbc jar为例子,安装命令: mvn install:install-file -Dgr ...
- What are some good books/papers for learning deep learning?
What's the most effective way to get started with deep learning? 29 Answers Yoshua Bengio, ...
- Software Engineer Title Ladder
http://changelog.ca/log/2013/08/09/software_engineer_title_ladder Within the software engineering pr ...
- Golang进程权限调度包runtime三大函数Gosched、Goexit、GOMAXPROCS
转自:https://www.cnblogs.com/wt645631686/p/9656046.html runtime.Gosched(),用于让出CPU时间片,让出当前goroutine的执行权 ...
- crontab命令详解
一. Crontab 介绍 1.crontab命令的功能是在一定的时间间隔调度一些命令的执行,我理解为windows下的任务计划. 2./etc/crontab 文件 在/etc目录下有一个cront ...
- 给centos7.3添加中文拼音输入法输入汉字
https://jingyan.baidu.com/article/86f4a73eaa0a6337d6526985.html