P3384 【模板】树链剖分
1.1K
通过
3.8K
提交
题目提供者HansBug 站长团
标签 高性能
难度 省选/NOI-
时空限制 1s / 128MB
提交 讨论 题解
最新讨论 更多讨论
为啥一个板子的难度设的这么…
哪位大佬来解决下本蒟蒻的疑…
三个点TLE是怎么回事
RE,70分。有大神能帮忙解决…
题目上的不解
90分,最后一个运行错误,大…
题目描述
如题,已知一棵包含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 \leq 10, M \leq 10 N≤10,M≤10
对于70%的数据: N \leq {10}^3, M \leq {10}^3 N≤10
3
,M≤10
3
对于100%的数据: N \leq {10}^5, M \leq {10}^5 N≤10
5
,M≤10
5
( 其实,纯随机生成的树LCA+暴力是能过的,可是,你觉得可能是纯随机的么233 )
样例说明:
树的结构如下:
各个操作如下:
故输出应依次为2、21(重要的事情说三遍:记得取模)
#include <cstdio>
#include <iostream>
#include <cstring>
#include <algorithm>
#define int long long
using namespace std;
const int N=100005;
int n,m,r,p,tot,dcnt;
int w[N],head[N*2],mp[N];
struct NODE{
int to,nex;
}ed[N*2];
struct node{
int fa,son,sz,dep,top,s,e;
}tr[N];//树链剖分
struct Segtree{
int l,r;
int sum,lazy;
}tree[4*N];
inline int read(){
int x=0,f=1;
char ch=getchar();
while(ch<'0'||ch>'9') {
if(ch=='-')f=-1;ch=getchar();}
while(ch<='9'&&ch>='0'){x=x*10+ch-'0';ch=getchar();}
return f*x;
}
void dfs1(int u){
tr[u].sz=1;
for(int i=head[u];i;i=ed[i].nex)
if(ed[i].to!=tr[u].fa){
tr[ed[i].to].fa=u;
tr[ed[i].to].dep=tr[u].dep+1;
dfs1(ed[i].to);
tr[u].sz+=tr[ed[i].to].sz;
if(tr[ed[i].to].sz>tr[tr[u].son].sz)
tr[u].son=ed[i].to;
}
}
void dfs2(int u,int top){
tr[u].top=top;
tr[u].s=++dcnt;
mp[dcnt]=u;//反向映射
if(tr[u].son){
dfs2(tr[u].son,top);
for(int i=head[u];i;i=ed[i].nex)
if(ed[i].to!=tr[u].fa&&ed[i].to!=tr[u].son)
dfs2(ed[i].to,ed[i].to);
}
tr[u].e=dcnt;
}
inline void addedge(int x,int y){
++tot;
ed[tot].nex=head[x];
head[x]=tot;
ed[tot].to=y;
}
inline void update(int u){
tree[u].sum=tree[u*2].sum+tree[u*2+1].sum;
return ;
}
void build(int b,int l,int r){
tree[b].l=l;
tree[b].r=r;
if(l==r){
tree[b].sum=w[mp[l]];
return ;
}
int mid=l+r>>1;
build(b*2,l,mid);
build(b*2+1,mid+1,r);
update(b);
}
inline void pushdown(int b){
if(tree[b].lazy){
if(tree[b].l!=tree[b].r){
tree[b*2].sum=tree[b*2].sum+tree[b].lazy*(tree[b*2].r-tree[b*2].l+1)%p;
tree[b*2+1].sum=tree[b*2+1].sum+tree[b].lazy*(tree[b*2+1].r-tree[b*2+1].l+1)%p;
tree[b*2].lazy+=tree[b].lazy;
tree[b*2+1].lazy+=tree[b].lazy;
}
tree[b].lazy=0;
}
return ;
}
void change(int b,int x,int y,int z){
if(y<tree[b].l||x>tree[b].r) return ;
if(tree[b].l>=x&&tree[b].r<=y){
tree[b].lazy+=z;
tree[b].sum=(tree[b].sum+(tree[b].r-tree[b].l+1)*z)%p;
return ;
}
pushdown(b);
change(2*b,x,y,z);
change(2*b+1,x,y,z);
update(b);
}
inline void add(int x,int y,int z){
int f1=tr[x].top;
int f2=tr[y].top;
while(f1!=f2){
if(tr[f1].dep<tr[f2].dep)
swap(f1,f2),swap(x,y);
change(1,tr[f1].s,tr[x].s,z);
x=tr[f1].fa;
f1=tr[x].top;
}
if(tr[x].dep<tr[y].dep)
change(1,tr[x].s,tr[y].s,z);
else change(1,tr[y].s,tr[x].s,z);
}
long long query(int num,int x,int y)
{
if(y<tree[num].l||x>tree[num].r)
return 0;
if(tree[num].l>=x&&tree[num].r<=y)
return tree[num].sum;
pushdown(num);
return (query(2*num,x,y)+query(2*num+1,x,y))%p;
}
inline int cha(int x,int y) {
int f1=tr[x].top,f2=tr[y].top;
long long ans=0;
while(f1!=f2)
{
if(tr[f1].dep<tr[f2].dep)
swap(f1,f2),swap(x,y);
ans=(ans+query(1,tr[f1].s,tr[x].s))%p;
x=tr[f1].fa;
f1=tr[x].top;
}
if(tr[x].dep<tr[y].dep)
ans+=query(1,tr[x].s,tr[y].s);
else
ans+=query(1,tr[y].s,tr[x].s);
return ans%p;
}
main(){
n=read();
m=read();
r=read();
p=read();
for(int i=1;i<=n;i++) w[i]=read();
for(int i=1;i<n;i++){
int x,y;
x=read();
y=read();
addedge(x,y);
addedge(y,x);
}
dfs1(r);
dfs2(r,r);
build(1,1,n);
for(int i=1;i<=m;i++){
int ort;
scanf("%lld",&ort);
if(ort==1){
int x,y,z;
x=read();
y=read();
z=read();
add(x,y,z);
}
if(ort==2){
int x,y;
x=read();
y=read();
printf("%lld\n",cha(x,y)%p);
}
if(ort==3){
int x,z;
x=read();
z=read();
change(1,tr[x].s,tr[x].e,z);
}
if(ort==4){
int x;
x=read();
printf("%lld\n",query(1,tr[x].s,tr[x].e)%p);
}
}
return 0;
}
哈哈哈