1 #include <stdio.h> 2 #include <cstring> 3 #include <iostream> 4 #include <string> 5 #include <algorithm> 6 #include <queue> 7 #include <vector> 8 #include <math.h> 9 #include <map> 10 11 #define LL long long 12 using namespace std; 13 const int maxn = 2e5 + 10; 14 15 struct Edge{ 16 int to,next; 17 }edge[maxn]; 18 19 int tot,head[maxn]; 20 21 void add_edge(int u,int v){ 22 edge[++tot] = Edge{v,head[u]}; 23 head[u] = tot; 24 } 25 26 int mod; 27 int v[maxn]; // 结点权值 28 int fa[maxn]; // 父亲 29 int dep[maxn]; // 深度 30 int siz[maxn]; // 大小 31 int son[maxn]; // 重儿子 32 33 // 第一遍的dfs可以得到深度,父亲,大小,重儿子 34 void dfs1(int u,int f){ // u是当前结点,f是u的父亲 35 fa[u] = f; 36 dep[u] = dep[f] + 1; 37 siz[u] = 1; 38 int maxsize = -1; // 判断是不是重儿子的一个临时变量 39 for (int i=head[u];~i;i=edge[i].next){ 40 int v = edge[i].to; 41 if (v == f) //如果是父亲肯定不可以 42 continue; 43 dfs1(v,u); 44 siz[u] += siz[v]; 45 if (siz[v] > maxsize){ 46 maxsize = siz[v]; 47 son[u] = v; // u的重儿子就是v 48 } 49 } 50 } 51 52 int tim; // 时间戳计数器 53 int dfn[maxn]; // 时间戳 54 int top[maxn]; //重链的顶部 55 int w[maxn]; // 结点权值dfs序 56 57 void dfs2(int u,int t){ // u是当前结点,t是当前结点的重链的头 58 dfn[u] = ++tim; 59 top[u] = t; 60 w[tim] = v[u]; 61 if (!son[u]) // 如果不存在重儿子,那么它就是叶子结点,退出 62 return; 63 dfs2(son[u],t); 64 for (int i=head[u];~i;i=edge[i].next){ 65 int v = edge[i].to; 66 if (v == fa[u] || v == son[u]) // 往上遍历肯定不可以了,因为前面的dfs2已经遍历了重儿子所以这里也没必要了 67 continue; 68 dfs2(v,v); // 此时这个肯定是轻儿子 69 } 70 } 71 72 struct segment_tree{ 73 int l,r,val; 74 int lazy; 75 }tree[maxn*4]; 76 77 void pushup(int nod){ 78 tree[nod].val = (tree[nod<<1].val + tree[(nod<<1)+1].val) % mod; 79 } 80 81 void pushdown(int nod){ 82 tree[nod<<1].lazy += tree[nod].lazy; 83 tree[(nod<<1)+1].lazy += tree[nod].lazy; 84 tree[nod<<1].val += (tree[nod<<1].r-tree[nod<<1].l + 1) * tree[nod].lazy % mod; 85 tree[(nod<<1)+1].val += (tree[(nod<<1)+1].r-tree[(nod<<1)+1].l+1) * tree[nod].lazy % mod; 86 tree[nod].lazy = 0; 87 } 88 89 void build(int l,int r,int nod=1){ 90 tree[nod].l = l; 91 tree[nod].r = r; 92 if (l == r){ 93 tree[nod].lazy = 0; 94 tree[nod].val = w[l] % mod; 95 return ; 96 } 97 int mid = (l+r)>>1; 98 build(l,mid,nod<<1); 99 build(mid+1,r,(nod<<1)+1); 100 pushup(nod); 101 } 102 103 void modify(int x,int y,int z,int k=1){ 104 int l = tree[k].l, r = tree[k].r; 105 if (x<= l && y>=r){ 106 tree[k].lazy += z; 107 tree[k].val += (r-l+1) * z; 108 tree[k].val %= mod; 109 return ; 110 } 111 if (tree[k].lazy) 112 pushdown(k); 113 int mid = (l+r)>>1; 114 if (x<=mid){ 115 modify(x,y,z,k<<1); 116 } 117 if (y>mid){ 118 modify(x,y,z,(k<<1)+1); 119 } 120 pushup(k); 121 } 122 123 int query(int x,int y,int k=1){ 124 int l = tree[k].l,r = tree[k].r; 125 if (x<=l && y>=r){ 126 return tree[k].val; 127 } 128 if (tree[k].lazy){ 129 pushdown(k); 130 } 131 int sum = 0,mid = (l+r)>>1; 132 if (x <= mid){ 133 sum += query(x,y,k<<1); 134 } 135 if (y > mid){ 136 sum += query(x,y,(k<<1)+1); 137 } 138 return sum % mod; 139 } 140 141 void mchain(int x,int y,int z){ // 结点x->结点y 最短路径上所有结点加z 142 z %= mod; 143 while (top[x] != top[y]){ 144 if (dep[top[x]] < dep[top[y]]) 145 swap(x,y); 146 modify(dfn[top[x]],dfn[x],z); 147 x = fa[top[x]]; 148 } 149 if (dep[x] > dep[y]) 150 swap(x,y); 151 modify(dfn[x],dfn[y],z); 152 } 153 154 int qchain(int x,int y){ // 查询x到y结点最短路径上所有节点的值之和 155 int ret = 0; 156 while (top[x] != top[y]){ 157 if (dep[top[x]] < dep[top[y]]) 158 swap(x,y); 159 ret += query(dfn[top[x]],dfn[x]); 160 x = fa[top[x]]; 161 } 162 if (dep[x] > dep[y]) 163 swap(x,y); 164 ret += query(dfn[x],dfn[y]); 165 return ret % mod; 166 } 167 168 void mson(int x,int z){ // 以x为根节点的子树内所有节点值都加上z 169 modify(dfn[x],dfn[x]+siz[x]-1,z); // 必定是连续的 170 } 171 172 int qson(int x){ // 以x为根节点的子树内所有节点值之和 173 return query(dfn[x],dfn[x]+siz[x]-1); 174 } 175 176 177 int main(){ 178 memset(head,-1, sizeof(head)); 179 int n,m,r; 180 scanf("%d%d%d%d",&n,&m,&r,&mod); 181 for (int i=1;i<=n;i++){ 182 scanf("%d",&v[i]); 183 } 184 for (int i=1;i<n;i++){ 185 int u,v; 186 scanf("%d%d",&u,&v); 187 add_edge(u,v); 188 add_edge(v,u); 189 } 190 dfs1(r,r); 191 dfs2(r,r); 192 build(1,n); 193 while (m--){ 194 int opt,x,y,z; 195 scanf("%d",&opt); 196 switch(opt){ 197 case 1: 198 scanf("%d%d%d",&x,&y,&z); 199 mchain(x,y,z); 200 break; 201 case 2: 202 scanf("%d%d",&x,&y); 203 printf("%d ",qchain(x,y)); 204 break; 205 case 3: 206 scanf("%d%d",&x,&z); 207 mson(x,z); 208 break; 209 case 4: 210 scanf("%d",&x); 211 printf("%d ",qson(x)); 212 break; 213 } 214 } 215 return 0; 216 }