题目:luogu3384.
不会树剖的点这里.
题目大意:在一棵树上支持:
1.格式1 x y z,表示将x到y的路径上的点权都加上z.
2.格式2 x y,表示查询x到y路径上的点权和.
3.格式3 x z,表示将x的子树节点的点权都加上z.
4.格式4 x,表示查询x的子树的点权和.
注:原题上所有答案对P取模.
这道题其实也很水,但是主要是有一个对子树进行操作的难点.
对子树进行操作的话,我们得先知道,树链剖分剖的时候,一棵子树的节点是在同一个区间内的.
那么左右端点呢?左端点肯定是树根,右端点我们可以通过这棵子树的size域计算出来.
那么这道题其实就是很裸的树链剖分了,代码如下:
#include<bits/stdc++.h>
using namespace std;
#define Abigail inline void
typedef long long LL;
const int N=100000;
struct node{
int dad,deep,son,size,top,dfn;
LL v;
}nod[N+9];
struct side{
int y,next;
}e[N*2+9];
struct tree{
int l,r;
LL sum,tag;
}tr[N*5];
int n,m,r,top,t,order[N+9],lin[N+9];
LL mod;
void ins(int X,int Y){
e[++top].y=Y;
e[top].next=lin[X];
lin[X]=top;
}
void dfs1(int k,int father){
nod[k].size=1;
nod[k].deep=nod[father].deep+1;
nod[k].dad=father;
for (int i=lin[k];i;i=e[i].next)
if (e[i].y^father) {
dfs1(e[i].y,k);
nod[k].size+=nod[e[i].y].size;
if (nod[e[i].y].size>nod[nod[k].son].size) nod[k].son=e[i].y;
}
}
void dfs2(int k,int start){
nod[k].top=start;
nod[k].dfn=++t;
order[t]=k;
if (nod[k].son) dfs2(nod[k].son,start);
for (int i=lin[k];i;i=e[i].next)
if (e[i].y^nod[k].dad&&e[i].y^nod[k].son) dfs2(e[i].y,e[i].y);
}
void update(int k,LL num){
tr[k].tag=(tr[k].tag+num)%mod;
tr[k].sum=(tr[k].sum+(tr[k].r-tr[k].l+1)*num%mod)%mod;
}
void pushup(int k){
tr[k].sum=(tr[k<<1].sum+tr[k<<1|1].sum)%mod;
}
void pushdown(int k){
update(k<<1,tr[k].tag);update(k<<1|1,tr[k].tag);
tr[k].tag=0LL;
}
void build(int L,int R,int k=1){
tr[k].l=L;tr[k].r=R;
if (L==R){
tr[k].sum=nod[order[L]].v;
return;
}
int mid=tr[k].l+tr[k].r>>1;
build(L,mid,k<<1),build(mid+1,R,k<<1|1);
pushup(k);
}
void add(int L,int R,LL num,int k=1){
if (L==tr[k].l&&R==tr[k].r){
update(k,num);
return;
}
pushdown(k);
int mid=tr[k].l+tr[k].r>>1;
if (R<=mid) add(L,R,num,k<<1);
else if (L>mid) add(L,R,num,k<<1|1);
else add(L,mid,num,k<<1),add(mid+1,R,num,k<<1|1);
pushup(k);
}
LL query(int L,int R,int k=1){
if (L==tr[k].l&&R==tr[k].r) return tr[k].sum;
int mid=tr[k].l+tr[k].r>>1;
pushdown(k);
if (R<=mid) return query(L,R,k<<1);
else if (L>mid) return query(L,R,k<<1|1);
else return (query(L,mid,k<<1)+query(mid+1,R,k<<1|1))%mod;
}
void Add(int u,int v,LL num){
while (nod[u].top^nod[v].top){
if (nod[nod[u].top].deep<nod[nod[v].top].deep) swap(u,v);
add(nod[nod[u].top].dfn,nod[u].dfn,num);
u=nod[nod[u].top].dad;
}
if (nod[u].deep>nod[v].deep) swap(u,v);
add(nod[u].dfn,nod[v].dfn,num);
}
LL Query(int u,int v){
LL sum=0LL;
while (nod[u].top^nod[v].top){
if (nod[nod[u].top].deep<nod[nod[v].top].deep) swap(u,v);
sum=(sum+query(nod[nod[u].top].dfn,nod[u].dfn))%mod;
u=nod[nod[u].top].dad;
}
if (nod[u].deep>nod[v].deep) swap(u,v);
return (sum+query(nod[u].dfn,nod[v].dfn))%mod;
}
Abigail into(){
scanf("%d%d%d%lld",&n,&m,&r,&mod);
for (int i=1;i<=n;i++){
scanf("%lld",&nod[i].v);
nod[i].v=(nod[i].v%mod+mod)%mod;
}
int x,y;
for (int i=1;i<n;i++){
scanf("%d%d",&x,&y);
ins(x,y);ins(y,x);
}
}
Abigail work(){
dfs1(r,0);
dfs2(r,r);
build(1,n);
int x,y,opt;
LL z;
for (int i=1;i<=m;i++){
scanf("%d",&opt);
switch (opt){
case 1:scanf("%d%d%lld",&x,&y,&z);
z=(z%mod+mod)%mod;
Add(x,y,z);
break;
case 2:scanf("%d%d",&x,&y);
printf("%lld\n",Query(x,y)%mod);
break;
case 3:scanf("%d%lld",&x,&z);
z=(z%mod+mod)%mod;
add(nod[x].dfn,nod[x].dfn+nod[x].size-1,z);
break;
case 4:scanf("%d",&x);
printf("%lld\n",query(nod[x].dfn,nod[x].dfn+nod[x].size-1)%mod);
break;
}
}
}
Abigail outo(){
}
int main(){
into();
work();
outo();
return 0;
}