蒟蒻刚学树剖,调了好久,无果后也跟题解区的DL们的代码对了好久。AC的是1,3两个点,其余全部RE。AC的两个点都跑的挺快的,我初步认为是数组的问题。
但是数组也开大了也没用,线段树和dfs也感觉没有打挂,每个数组的类型应该没错(全开long long 试了一下也是这样),请求大佬帮看。
感谢各位大佬的帮助。
Code + 一点简单的注释:
#include<bits/stdc++.h>
#define maxn 200005
#define rg register
using namespace std;
inline void read(int &x){
int f=1;x=0;char c=getchar();
while (c<'0'||c>'9') {if (c=='-') f=-1;c=getchar();}
while (c>='0'&&c<='9') {x=x*10+c-'0';c=getchar();}
x*=f;
}
inline void readl(long long &x){
int f=1;x=0;char c=getchar();
while (c<'0'||c>'9') {if (c=='-') f=-1;c=getchar();}
while (c>='0'&&c<='9') {x=x*10+c-'0';c=getchar();}
x*=f;
}//两个快读
int son[maxn],size[maxn],id[maxn], fa[maxn],deep[maxn],cnt, top[maxn];
//重儿子 ,子树大小 ,再次标的序号,爸爸 ,深度 ,标号下标,重链顶端
int n,m,root;
long long mod,zz[maxn],w[maxn];
struct node{
long long sum,add;
}f[maxn<<2];
int T,h[maxn];
struct yyy{
int to,z;
inline void add(int x,int y){
to=y;z=h[x];h[x]=T;
}
}a[maxn<<1];//链式前向星
long long k;int head,tail;
inline void Pushup(int rt){f[rt].sum=f[rt<<1].sum+f[rt<<1|1].sum;f[rt].sum%=mod;}
inline void Pushdown(int l,int r,int rt){
if (f[rt].add){
int m=l+r>>1;
f[rt<<1].add+=f[rt].add;f[rt<<1|1].add+=f[rt].add;
f[rt<<1].add%=mod;f[rt<<1|1].add%=mod;
f[rt<<1].sum+=f[rt].add*(m-l+1);f[rt<<1].sum%=mod;
f[rt<<1|1].sum+=f[rt].add*(r-m);f[rt<<1|1].sum%=mod;
f[rt].add=0;
}
}//下推标记
inline void Build(int l,int r,int rt){
if (l==r){
f[rt].sum=w[l];
return;
}
int m=l+r>>1;
Build(l,m,rt<<1);
Build(m+1,r,rt<<1|1);
Pushup(rt);
return;
}//建树
inline void Update(int l,int r,int rt){
if (head<=l&&r<=tail){
f[rt].add+=k;f[rt].add%=mod;
f[rt].sum+=k*(r-l+1);f[rt].sum%=mod;
return;
}
Pushdown(l,r,rt);
int m=l+r>>1;
if (head<=m) Update(l,m,rt<<1);
if (tail>m) Update(m+1,r,rt<<1|1);
Pushup(rt);
return;
}//更新
inline long long Query(int l,int r,int rt){
if (head<=l&&r<=tail) return f[rt].sum%mod;
Pushdown(l,r,rt);
int m=l+r>>1;long long ans=0;
if (head<=m) ans+=Query(l,m,rt<<1);
if (tail>m) ans+=Query(m+1,r,rt<<1|1);
return ans%mod;
}//询问
//递归式线段树
inline void dfs1(int x,int pre){
rg int i,Max=0;
deep[x]=deep[pre]+1;size[x]=1;fa[x]=pre;
for (i=h[x];i+1;i=a[i].z)
if (a[i].to!=pre){
dfs1(a[i].to,x);size[x]+=size[a[i].to];
if (size[a[i].to]>Max) Max=size[a[i].to],son[x]=a[i].to;
}
}
inline void dfs2(int x,int v){
top[x]=v;id[x]=++cnt;w[cnt]=zz[x];
rg int i;
if (!son[x]) return;
dfs2(son[x],v);
for (i=h[x];i+1;i=a[i].z)
if (a[i].to!=son[x]&&a[i].to!=fa[x])
dfs2(a[i].to,a[i].to);
}//树剖预处理
inline void Add1(int x,int y,long long z){
k=z;
while (top[x]^top[y]){
if (deep[x]<deep[y]) x^=y^=x^=y;
head=id[top[x]];tail=id[x];Update(1,n,1);
x=fa[top[x]];
}
if (deep[x]<deep[y]) x^=y^=x^=y;
head=id[y];tail=id[x];Update(1,n,1);
}//操作1
inline long long Query1(int x,int y){
rg long long ans=0;
while (top[x]^top[y]){
if (deep[x]<deep[y]) x^=y^=x^=y;
head=id[top[x]];tail=id[x];ans+=Query(1,n,1);
x=fa[top[x]];
}
if (deep[x]<deep[y]) x^=y^=x^=y;
head=id[y];tail=id[x];ans+=Query(1,n,1);ans%=mod;
return ans;
}//操作2
inline void Add2(int x,long long z){
k=z;head=id[x];tail=id[x]+size[x]-1;Update(1,n,1);
}//操作3
inline long long Query2(int x){
head=id[x];tail=id[x]+size[x]-1;
return Query(1,n,1)%mod;
}//操作4
int main(){
//freopen("1.in","r",stdin);
memset(h,-1,sizeof(h));
rg int i,x,y,op;rg long long z;
read(n);read(m);read(root);readl(mod);
for (i=1;i<=n;i++) readl(zz[i]),zz[i]%=mod;
for (i=1;i<n;i++){
read(x);read(y);
a[++T].add(x,y);
a[++T].add(y,x);
}//存边
dfs1(root,-1);dfs2(root,root),Build(1,n,1);
for (i=1;i<=m;i++){
read(op);
if (op==1) read(x),read(y),readl(z),Add1(x,y,z);
else if (op==2) read(x),read(y),printf("%lld\n",Query1(x,y));
else if (op==3) read(x),readl(z),Add2(x,z);
else read(x),printf("%lld\n",Query2(x));
}
return 0;
}