给定n个点以及每个点的权值,要你处理接下来的m个操作。操作有4种。操作从0到3编号。点从1到n编号。
0:后接两个整数(x,y),代表询问从x到y的路径上的点的权值的xor和。保证x到y是联通的。
1:后接两个整数(x,y),代表连接x到y,若x到y已经联通则无需连接。
2:后接两个整数(x,y),代表删除边(x,y),不保证边(x,y)存在。
3:后接两个整数(x,y),代表将点x上的权值变成y。
输入输出格式
输入格式:
第1行两个整数,分别为n和m,代表点数和操作数。
第2行到第n+1行,每行一个整数,整数在[1,10^9]内,代表每个点的权值。
第n+2行到第n+m+1行,每行三个整数,分别代表操作类型和操作所需的量。
输出格式:
对于每一个0号操作,你须输出x到y的路径上点权的xor和。
输入输出样例
输入样例#1:
3 3
1
2
3
1 1 2
0 1 2
0 1 1
输出样例#1:
3
1
说明
数据范围: ,
树剖板子题
不过细节码量还是有点大
// luogu-judger-enable-o2
#include<bits/stdc++.h>
using namespace std;
#define mid ((l+r)/2)
inline int read(){
char ch=getchar();
int res=0;
while(!isdigit(ch)) ch=getchar();
while(isdigit(ch)) res=(res<<3)+(res<<1)+(ch^48),ch=getchar();
return res;
}
int sum[400005],mark[400005],n,m,r,mod,adj[200005],nxt[200005],to[200004],cnt;
int fa[200005],son[200005],id[200005],dep[200005],siz[200005],top[200005],w[200005],val[200005];
inline void addedge(int u,int v){
nxt[++cnt]=adj[u],adj[u]=cnt,to[cnt]=v;
nxt[++cnt]=adj[v],adj[v]=cnt,to[cnt]=u;
}
int pushup(int rt)
{
sum[rt] = (sum[rt << 1] + sum[rt << 1 | 1]) % mod;
}
inline void pushdown(int u,int len)
{
if(mark[u])
{
mark[u*2]+=mark[u];
mark[(u*2)+1]+=mark[u];
sum[u*2]+=mark[u]*(len-(len>>1));
sum[u*2]%=mod;
sum[(u*2)+1]+=mark[u]*(len>>1);
sum[(u*2)+1]%=mod;
mark[u]=0;
}
}
inline void buildtree(int u,int l,int r,int dep)
{
if(l==r)
{
sum[u]=val[l];
sum[u]%=mod;
return ;
}
buildtree(u*2,l,mid,dep+1);
buildtree((u*2)+1,mid+1,r,dep+1);
pushup(u);
}
void update(int u,int l,int r,int L, int R, int c)
{
if (L <= l && r <= R)
{
mark[u] += c;
sum[u] += c * (r - l + 1);
sum[u] %= mod;
return;
}
pushdown(u, r - l + 1);
int m = (l + r) >> 1;
if (L <= m)
update(u*2,l,m,L, R, c);
if (R > m)
update((u*2)+1,m+1,r,L, R, c);
pushup(u);
}
inline int query(int u,int l,int r,int st,int des)
{
if(l>des||r<st) return 0;
int ans=0;
if(st<=l&&r<=des)
{
return sum[u];
}
pushdown(u,r-l+1);
if(st<=mid)
{
ans+=query(u*2,l,mid,st,des);
ans%=mod;
}
if(mid<des)
{
ans+=query((u*2)+1,mid+1,r,st,des);
ans%=mod;
}
return ans;
}
inline void dfs1(int u,int f)
{
dep[u]=dep[f]+1;
fa[u]=f,siz[u]=1;
int maxs=-1;
for(int e=adj[u];e;e=nxt[e])
{
int v=to[e];
if(v==f) continue;
dfs1(v,u);
siz[u]+=siz[v];
if(siz[v]>maxs)
{
son[u]=v;
maxs=siz[v];
}
}
}
inline void dfs2(int u,int topfa)
{
id[u]=++cnt;
val[cnt]=w[u];
top[u]=topfa;
if(!son[u]) return;
dfs2(son[u],topfa);
for(int e=adj[u];e;e=nxt[e])
{
int v=to[e];
if(v==son[u]||v==fa[u]) continue;
dfs2(v,v);
}
}
inline void uprange(int x,int y,int k)
{
k%=mod;
while(top[x]!=top[y])
{
if(dep[top[x]]<dep[top[y]]) swap(x,y);
update(1,1,n,id[top[x]],id[x],k);
x=fa[top[x]];
}
if(dep[x]>dep[y]) swap(x,y);
update(1,1,n,id[x],id[y],k);
}
inline int qrange(int x,int y)
{
int ans=0;
while(top[x]!=top[y])
{
if(dep[top[x]]<dep[top[y]]) swap(x,y);
ans+=query(1,1,n,id[top[x]],id[x]);
ans%=mod;
x=fa[top[x]];
}
if(dep[x]>dep[y]) swap(x,y);
ans+=query(1,1,n,id[x],id[y]);
return ans%mod;
}
inline void upson(int x,int k){
update(1,1,n,id[x],id[x]+siz[x]-1,k);
}
inline int qson(int x)
{
return query(1,1,n,id[x],id[x]+siz[x]-1);
}
int main()
{
int u, v;
n=read(),m=read(),r=read(),mod=read();
for (int i = 1; i <= n; i++)
w[i]=read();
for (int i = 1; i <= n - 1; i++)
{
u=read(),v=read();
addedge(u, v);
}
cnt=0;
dfs1(r, 0);
dfs2(r, r);
buildtree(1, 1,n,1);
while (m--)
{
int op, x, y, z;
op=read();
if (op == 1)
{
x=read(),y=read(),z=read();
uprange(x, y, z);
}
else if (op == 2)
{
x=read(),y=read();
printf("%d
", qrange(x, y));
}
else if (op == 3)
{
x=read(),z=read();
upson(x, z);
}
else if (op == 4)
{
x=read();
printf("%d
", qson(x));
}
}
return 0;
}