题目描述
如题,已知一棵包含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
#include <bits/stdc++.h>
using namespace std;
const int maxn=1e5+100;
struct edge
{
int v,next;
} e[maxn*2];
struct Tree
{
int sum,l,r,lazy;
} tree[maxn*4];
int top[maxn],tim,dfn[maxn],son[maxn],w[maxn],head[maxn],a[maxn],siz[maxn],deep[maxn],fa[maxn],mod,t;
void add(int u,int v)
{
t++;
e[t].v=v;
e[t].next=head[u];
head[u]=t;
}
void pushup(int rt)
{
tree[rt].sum=(tree[rt<<1].sum+tree[rt<<1|1].sum)%mod;
}
void pushdown(int rt,int l,int r)
{
if (tree[rt].lazy==0)
return;
int mid=(l+r)>>1;
tree[rt<<1].lazy+=tree[rt].lazy;
tree[rt<<1|1].lazy+=tree[rt].lazy;
tree[rt<<1].sum=(tree[rt<<1].sum+tree[rt].lazy*(mid-l+1))%mod;
tree[rt<<1|1].sum=(tree[rt<<1|1].sum+tree[rt].lazy*(r-mid))%mod;
tree[rt].lazy=0;
}
void build(int rt,int l,int r)
{
tree[rt].l=l;
tree[rt].r=r;
tree[rt].sum=0;
if (l==r)
{
tree[rt].sum=w[l];
return;
}
int mid=(l+r)>>1;
build(rt<<1,l,mid);
build (rt<<1|1,mid+1,r);
pushup(rt);
}
void update(int rt,int l,int r,int z)
{
if (l<=tree[rt].l&&tree[rt].r<=r)
{
tree[rt].lazy+=z;
tree[rt].sum+=z*(tree[rt].r-tree[rt].l+1);
return;
}
pushdown(rt,tree[rt].l,tree[rt].r);
int mid=(tree[rt].l+tree[rt].r)>>1;
if (l<=mid)
{
update(rt<<1,l,r,z);
}
if (r>mid)
{
update(rt<<1|1,l,r,z);
}
pushup(rt);
}
void dfs1(int u,int f)
{
deep[u]=deep[f]+1;
siz[u]=1;
fa[u]=f;
int maxsiz=-1;
for (int i=head[u]; i; i=e[i].next)
{
int v=e[i].v;
if (v==f)
{
continue;
}
dfs1(v,u);
siz[u]+=siz[v];
if (siz[v]>maxsiz)
{
maxsiz=siz[v];
son[u]=v;
}
}
}
int query(int rt,int l,int r)
{
if (l<=tree[rt].l&&tree[rt].r<=r)
{
return tree[rt].sum%mod;
}
pushdown(rt,tree[rt].l,tree[rt].r);
int ret=0;
int mid=(tree[rt].l+tree[rt].r)>>1;
if (l<=mid)
ret=(ret+query(rt<<1,l,r))%mod;
if (r>mid)
ret=(ret+query(rt<<1|1,l,r))%mod;
return ret;
}
void dfs2(int u,int Top)
{
dfn[u]=++tim;
w[tim]=a[u];
top[u]=Top;
if (!son[u])
{
return;
}
dfs2(son[u],Top);
for (int i=head[u]; i; i=e[i].next)
{
int v=e[i].v;
if (v==fa[u]||v==son[u])
{
continue;
}
dfs2(v,v);
}
}
void update1(int x,int y,int z)
{
z=z%mod;
while (top[x]!=top[y])
{
if (deep[top[x]]<deep[top[y]])
{
swap(x,y);
}
update(1,dfn[top[x]],dfn[x],z);
x=fa[top[x]];
}
if (deep[x]>deep[y])
{
swap(x,y);
}
update(1,dfn[x],dfn[y],z);
}
int query1(int x,int y)
{
int ret=0;
while (top[x]!=top[y])
{
if (deep[top[x]]<deep[top[y]])
{
swap(x,y);
}
ret+=query(1,dfn[top[x]],dfn[x]);
x=fa[top[x]];
}
if (deep[x]>deep[y])
{
swap(x,y);
}
ret+=query(1,dfn[x],dfn[y]);
return ret%mod;
}
int main()
{
// freopen("1.txt","w",stdout);
int n,m,r;
scanf("%d%d%d%d",&n,&m,&r,&mod);
for (int i=1; i<=n; ++i)
{
scanf("%d",&a[i]);
}
for (int i=1,u,v; i<n; i++)
{
scanf("%d%d",&u,&v);
add(u,v);
add(v,u);
}
dfs1(r,0);
dfs2(r,r);
build(1,1,n);
while (m--)
{
int op;
scanf("%d",&op);
if (op==1)
{
int x,y,z;
scanf("%d%d%d",&x,&y,&z);
update1(x,y,z);
}
if (op==2)
{
int x,y;
scanf("%d%d",&x,&y);
printf("%d
",query1(x,y));
}
if (op==3)
{
int x,z;
scanf("%d%d",&x,&z);
update(1,dfn[x],dfn[x]+siz[x]-1,z);
}
if (op==4)
{
int x;
scanf("%d",&x);
printf("%d
",query(1,dfn[x],dfn[x]+siz[x]-1));
}
}
return 0;
}