niweizheni @ 2024-07-10 17:25:13
求大佬看看错在哪里了,调了一下午 28pts #2 #3 #11 AC 其余全wa
#include<bits/stdc++.h>
using namespace std;
const int N=1e5+15;
int n,m,r,p;
int h[N*2],to[N*2],ne[2*N],idx=1;
int a[N*2],aid[N*2];//初始值
int sum[N*4],lazy[N*4],ll[N*4],rr[N*4];//线段树数组(和,懒标记)
int son[N*2],id[N*2],fa[N*2],cnt=0,dep[N*2],ssize[N*2],top[N*2];
//son表示他的重儿子,id表示他的编号,fa表示他的父亲节点,cnt是编号记录器,dep是他的深度,ssize是他儿子加上他自己的大小,top是他重链的顶端
int ans=0,res=0;//答案
void add(int u,int v)//链式前向星
{
to[idx]=v;
ne[idx]=h[u];
h[u]=idx++;
}
//向上累加
void push_up(int x)
{
sum[x]=(sum[x*2]%p+sum[x*2+1]%p)%p;
}
//懒标记下放
void push_down(int x)
{
if(lazy[x])
{
lazy[x*2]=lazy[x];
lazy[x*2+1]=lazy[x];
sum[x*2]+=lazy[x]*(rr[x*2]-ll[x*2]+1);
sum[x*2]%=p;
sum[x*2+1]+=lazy[x]*(rr[x*2+1]-ll[x*2+1]+1);
sum[x*2+1]%=p;
lazy[x]=0;
}
}
//建立线段树
void build(int x,int l,int r)
{
lazy[x]=0;
ll[x]=l;
rr[x]=r;
if(l==r)
{
//cout<<aid[l]<<endl;
sum[x]=aid[l];//如果是叶子节点就赋值回溯
sum[x]%=p;
return;
}
int mid=(l+r)>>1;
build(x*2,l,mid);//找左儿子
build(x*2+1,mid+1,r);//找右儿子
push_up(x);
}
//区间修改
void update(int x,int l,int r,int k)
{
//cout<<x<<endl;
//cout<<l<<" "<<ll[x]<<" "<<rr[x]<<" "<<r<<" "<<x<<endl;
if(l<=ll[x]&&rr[x]<=r)
{
lazy[x]+=k;
sum[x]+=k*(rr[x]-ll[x]+1);
sum[x]%=p;
return;
}
push_down(x);
int mid=(ll[x]+rr[x])/2;
if(l<=mid)
{
update(x*2,l,r,k);
}
if(r>mid)
{
update(x*2+1,l,r,k);
}
push_up(x);
}
//区间查询
void query(int x,int l,int r)
{
//cout<<x<<endl;
if(l<=ll[x]&&rr[x]<=r)
{
//cout<<sum[x]<<endl;
res+=sum[x];
res%=p;
return;
}
push_down(x);
int mid=(ll[x]+rr[x])>>1;
if(l<=mid)
{
query(x*2,l,r);
}
if(r>mid)
{
query(x*2+1,l,r);
}
}
//------------------------------上为线段树,下为重链剖分-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------
//第一次深搜,预处理出son,dep,fa,ssize
void dfs(int u,int f,int deep)
{
//cout<<u<<" ";
dep[u]=deep;//预处理dep
fa[u]=f;//预处理fa
ssize[u]=1;//把自己的子树加上自己
int maxson=-1;
for(int i=h[u];i!=-1;i=ne[i])//用链式前向星循环
{
int v=to[i];
if(v==f)//不能往回走,避免卡住
{
continue;
}
dfs(v,u,deep+1);//深搜
ssize[u]+=ssize[v];//加上自己的儿子的子树大小(预处理ssize)
if(ssize[v]>maxson)
{
son[u]=v;//预处理son
maxson=ssize[v];
}
}
}
//第二次深搜,预处理id,aid,top
void dp_dfs(int u,int topf)//topf是u所在树链开始地点(顶点)
{
//cout<<u<<" ";
id[u]=++cnt;//记录新点编号
aid[cnt]=a[u];//记录新点点权
top[u]=topf;//记录所在树链起点
if(!son[u])
{
return;//没有儿子就返回
}
dp_dfs(son[u],topf);//继续找重儿子
for(int i=h[u];i!=-1;i=ne[i])
{
int v=to[i];
if(v==fa[u]||v==son[u])//判断轻儿子
{
continue;
}
dp_dfs(v,v);//每个轻儿子都有以自己为顶点的子树
}
}
void updrange(int x,int y,int z)//区间修改(做和)
{
z%=p;
while(top[x]!=top[y])
{
if(dep[top[x]]<dep[top[y]])
{
swap(x,y);
}
update(1,id[top[x]],id[x],z);
x=fa[top[x]];
}
if(dep[x]>dep[y])
{
swap(x,y);
}
update(1,id[x],id[y],z);
}
//
int qrange(int x,int y)
{
ans=0;
while(top[x]!=top[y])
{
res=0;
if(dep[top[x]]<dep[top[y]])
{
swap(x,y);
}
query(1,id[top[x]],id[x]);
ans+=res;
ans%=p;
x=fa[top[x]];
}
res=0;
if(dep[x]>dep[y])
{
swap(x,y);
}
query(1,id[x],id[y]);
ans+=res;
ans%=p;
return ans;
}
//更改子树值
void upson(int x,int k)
{
update(1,id[x],id[x]+ssize[x]-1,k);
}
//子树和相加
int qson(int x)
{
res=0;
query(1,id[x],id[x]+ssize[x]-1);
return res;
}
int main()
{
memset(h,-1,sizeof(h));
scanf("%d%d%d%d",&n,&m,&r,&p);
for(int i=1;i<=n;i++)//输入每个点的点权
{
cin>>a[i];
}
for(int i=1;i<n;i++)//建树
{
int x,y;
scanf("%d%d",&x,&y);
add(x,y);//使用链式前向星
add(y,x);
}
dfs(r,0,1);//执行第一次深搜,预处理出son,dep,fa,ssize
//
dp_dfs(r,r);//执行第二次深搜,预处理出id,top,aid
//cout<<1;
build(1,1,n);//建立线段树
for(int i=1;i<=m;i++)
{
int q;
scanf("%d",&q);
if(q==1)
{
int x,y,z;
scanf("%d%d%d",&x,&y,&z);
updrange(x,y,z);
}
else if(q==2)
{
int x,y;
scanf("%d%d",&x,&y);
printf("%d\n",qrange(x,y));
}
else if(q==3)
{
int x,y;
scanf("%d%d",&x,&y);
upson(x,y);
}
else if(q==4)
{
int x;
scanf("%d",&x);
printf("%d\n",qson(x));
}
}
return 0;
}
by Little_Cancel_Sunny @ 2024-07-10 17:30:32
注意此处lazy数组应该是加上父亲节点的lazy,而不是等于
lazy[x*2]+=lazy[x];
lazy[x*2+1]+=lazy[x];
by niweizheni @ 2024-07-10 17:31:24
谢谢DaLao
by niweizheni @ 2024-07-10 18:43:58
大佬太好了,大佬一改就A了