AfterFullStop @ 2023-01-31 16:20:05
找到眼瞎都没找出来
#include<bits/stdc++.h>
#define ll long long
#define int long long
#define ri register int
#define maxn 500005
using namespace std;
inline ll read(){
ll x=0,f=1;
char ch=getchar();
while(ch<'0'||ch>'9'){
if(ch=='-')
f=-1;
ch=getchar();
}
while(ch>='0'&&ch<='9'){
x=x*10+ch-48;
ch=getchar();
}
return x*f;
}
inline void write(ll n){
if(n<0){
putchar('-');
n=-n;
}
if(n>9)
write(n/10);
putchar(n%10+'0');
}
ll n,m,r,p;
ll a[maxn],b[maxn];
int cnt,head[maxn],to[maxn],nxt[maxn];
int siz[maxn],dep[maxn],fa[maxn],son[maxn],top[maxn],id[maxn];
//线段树部分
struct tn{
int l,r;
ll s,lazy;
}tree[maxn<<2];
void build(int i,int l,int r){
tree[i].l=l;tree[i].r=r;
if(l==r){
tree[i].s=b[l];
return;
}
int mid=l+r>>1;
build(i<<1,l,mid);
build(i<<1|1,mid+1,r);
tree[i].s=tree[i<<1].s+tree[i<<1|1].s;
tree[i].s%=p;
}
inline void push(int i){
if(tree[i].lazy){
tree[i<<1].lazy+=tree[i].lazy;
tree[i<<1].s+=tree[i].lazy*(tree[i<<1].r-tree[i<<1].l+1)%p;
tree[i<<1|1].lazy+=tree[i].lazy;
tree[i<<1|1].s+=tree[i].lazy*(tree[i<<1|1].r-tree[i<<1|1].l+1)%p;
tree[i<<1].s%=p;
tree[i<<1|1].s%=p;
tree[i<<1].lazy%=p;
tree[i<<1|1].lazy%=p;
tree[i].lazy=0;
}
}
inline void change(int i,int l,int r,ll d){
if(tree[i].l>=l&&tree[i].r<=r){
tree[i].lazy=(tree[i].lazy+d)%p;
tree[i].s=(tree[i].s+d*(tree[i].r-tree[i].l+1)%p)%p;
return;
}push(i);
int mid=(tree[i].l+tree[i].r)>>1;
if(l<=mid)change(i<<1,l,r,d);
if(r>mid)change(i<<1|1,l,r,d);
tree[i].s=(tree[i<<1].s+tree[i<<1|1].s)%p;
}
inline ll query(int i,int l,int r){
if(tree[i].l>=l&&tree[i].r<=r)
return tree[i].s%p;
push(i);
int mid=(tree[i].l+tree[i].r)>>1;
ll val=0;
if(l<=mid)val=(val+query(i<<1,l,r))%p;
if(r>mid)val=(val+query(i<<1|1,l,r))%p;
return val%p;
}
//线段树部分结束
inline void add(int u,int v){
++cnt;
to[cnt]=v;
nxt[cnt]=head[u];
head[u]=cnt;
}
void dfs1(int u){
int ms=0;
siz[u]=1;
for(ri e=head[u];e;e=nxt[e]){
int v=to[e];
if(v==fa[u])continue;
fa[v]=u;
dep[v]=dep[u]+1;
dfs1(v);
siz[u]+=siz[v];
if(siz[v]>ms){
ms=siz[v];
son[u]=v;
}
}
}
int tot=0;
void dfs2(int u,int topf){
id[u]=++tot;
b[id[u]]=a[u];
top[u]=topf;
if(son[u])dfs2(son[u],topf);
for(ri e=head[u];e;e=nxt[e]){
int v=to[e];
if(v!=fa[u]&&v!=son[u])dfs2(v,v);
}
}
inline void uRange(int x,int y,ll z){
while(top[x]!=top[y]){
if(dep[top[x]]<dep[top[y]])swap(x,y);
change(1,id[x],id[top[x]],z);
x=fa[top[x]];
}
if(dep[x]>dep[y])swap(x,y);
change(1,id[x],id[y],z);
}
inline ll qRange(int x,int y){
ll ans=0;
while(top[x]!=top[y]){
if(dep[top[x]]<dep[top[y]])swap(x,y);
ans=(ans+query(1,id[x],id[top[x]]))%p;
x=fa[top[x]];
}
if(dep[x]>dep[y])swap(x,y);
return (ans+query(1,id[x],id[y]))%p;
}
inline void uTree(int u,ll k){
change(1,id[u],id[u]+siz[u]-1,k);
}
inline ll qTree(int u){
return query(1,id[u],id[u]+siz[u]-1);
}
int op,x,y,z;
signed main(){
n=read();m=read();r=read();p=read();
for(ri i=1;i<=n;i++)a[i]=read()%p;
for(ri i=1,u,v;i<n;i++){
u=read();v=read();
add(u,v);add(v,u);
}
dfs1(r);
dfs2(r,r);
build(1,1,n);
while(m--){
op=read();
if(op==1){
x=read();y=read();z=read();
uRange(x,y,z);
}if(op==2){
x=read();y=read();
write(qRange(x,y));printf("\n");
}if(op==3){
x=read();y=read();
uTree(x,y);
}if(op==4){
x=read();
write(qTree(x));printf("\n");
}
}
return 0;
}
by smallpeter @ 2023-01-31 16:54:01
@LemonAndMelon 树剖过程中错了
by smallpeter @ 2023-01-31 16:54:53
inline void uRange(int x,int y,ll z){
while(top[x]!=top[y]){
if(dep[top[x]]<dep[top[y]])swap(x,y);
change(1,id[x],id[top[x]],z);
x=fa[top[x]];
}
if(dep[x]>dep[y])swap(x,y);
change(1,id[x],id[y],z);
}
inline ll qRange(int x,int y){
ll ans=0;
while(top[x]!=top[y]){
if(dep[top[x]]<dep[top[y]])swap(x,y);
ans=(ans+query(1,id[x],id[top[x]]))%p;
x=fa[top[x]];
}
if(dep[x]>dep[y])swap(x,y);
return (ans+query(1,id[x],id[y]))%p;
}
里面while循环的query的id[x]和id[top[x]]写反了
by smallpeter @ 2023-01-31 16:56:20
top[x]是x的祖先,那dfs序肯定是top[x]要小
by AfterFullStop @ 2023-01-31 17:00:26
@small_peter 傻了,已AC,感谢