YGW6 @ 2024-07-10 15:44:04
#include<iostream>
#include<cmath>
#include<string>
#include<string.h>
#include<algorithm>
using namespace std;
const int N=1e5+5;
int n,m,r,mod;
int answer;
int w[N];
int cnt;
int fa[N],dep[N],size[N],son[N],top[N],id[N],wt[N];
/*
fa[u]:u在树中的父亲
dep[u]:u节点的深度
size[u]:u的子树节点数(子树大小)
son[u]:u的重儿子
top[u]:u所在重链的顶部节点
id[x]:新的编号
wt[y]:新编号的点权
*/
struct edge
{
int u,v;
}e[N*2];
int h[N*2],tot;
int sum[N*4],lazy[N*4];
void add(int u,int v)
{
e[++tot].v=v;
e[tot].u=h[u];
h[u]=tot;
}
void dfs1(int u,int f,int deep)
{
dep[u]=deep; //标记深度
fa[u]=f; //标记节点的父亲
size[u]=1; //记录每个节点子树大小
int maxson=-1; //记录重儿子数量
for(int i=h[u];i!=-1;i=e[i].u)
{
int v=e[i].v;
if(v==f)
continue;
dfs1(v,u,deep+1);
size[u]+=size[v];
if(size[v]>maxson) //儿子里最多 size 就是重儿子
{
son[u]=v; //标记u的重儿子为 v
maxson=size[v];
}
}
}
//处理出top[],wt[],id[]
void dfs2(int u,int topf)
{
id[u]=++cnt; //每个节点的新编号
wt[cnt]=w[u]; //新编号的对应权值
top[u]=topf; //标记每个重链的顶端
if(!son[u]) //没有儿子时返回
return ;
dfs2(son[u],topf); //搜索下一个重儿子
for(int i=h[u];i!=-1;i=e[i].u)
{
int v=e[i].v;
if(v==fa[u] or v==son[u]) //处理轻儿子
continue;
dfs2(v,v); //每一个轻儿子都有一个从自己开始的链
}
}
void push_up(int u)
{
sum[u]=(sum[2*u]+sum[2*u+1])%mod;
}
void push_down(int u,int len) //下放lazy标记
{
lazy[2*u]+=lazy[u];
lazy[2*u+1]+=lazy[u];
sum[2*u]+=lazy[u]*(len-len/2);
sum[2*u]%=mod;
sum[2*u+1]+=lazy[u]*len/2;
sum[2*u+1]%=mod;
lazy[u]=0;
}
void build(int u,int l,int r)
{
lazy[u]=0;
if(l==r)
{
sum[u]=wt[l]; //新的编号点权
sum[u]%=mod;
return ;
}
int mid=(l+r)/2;
build(2*u,l,mid);
build(2*u+1,mid+1,r);
push_up(u);
}
void update(int L,int R,int c,int l,int r,int u)
{
if(L<=l&&R>=r)
{
lazy[u]+=c;
sum[u]+=c*(r-l+1);
sum[u]%=mod;
return ;
}
if(lazy[u])
push_down(u,r-l+1);
int mid=(l+r)/2;
if(L<=mid)
update(L,R,c,l,mid,2*u);
if(R>mid)
update(L,R,c,mid+1,r,2*u+1);
push_up(u);
}
void updrange(int x,int y,int k)
{
k%=mod;
while(top[x]!=top[y])
{
if(dep[top[x]]<dep[top[y]]) //使x深度较大
swap(x,y);
update(id[top[x]],id[x],k,1,n,1);
x=fa[top[x]];
}
if(dep[x]>dep[y]) //使x深度较小
swap(x,y);
update(id[x],id[y],k,1,n,1);
}
void query(int L,int R,int l,int r,int u)
{
if(L<=l&&R>=r)
{
answer+=sum[u];
answer%=mod;
return ;
}
if(lazy[u])
push_down(u,r-l+1);
int mid=(l+r)/2;
if(L<=mid)
query(L,R,l,mid,2*u);
if(R>mid)
query(L,R,mid+1,r,2*u+1);
}
int qrange(int x,int y)
{
int ans=0;
while(top[x]!=top[y]) //当两个点不在同一条链上
{
if(dep[top[x]]<dep[top[y]]) //使x深度较大
swap(x,y);
answer=0;
query(id[top[x]],id[x],1,n,1); //ans加上x点到x所在链顶端这一段区间的点权和
ans+=answer;
ans%=mod;
x=fa[top[x]]; //x跳到x所在链顶端的这个点的上面一个点
}
//当两个点处于同一条链
if(dep[x]>dep[y]) //使x深度较小
swap(x,y);
answer=0;
query(id[x],id[y],1,n,1);
ans+=answer;
ans%=mod;
return ans;
}
void upson(int x,int k)
{
update(id[x],id[x]+size[x]-1,k,1,n,1); //子树区间右端点为id[x]+siz[x]-1
}
int qson(int x)
{
answer=0;
query(id[x],id[x]+size[x]-1,1,n,1);
return answer;
}
int main()
{
ios::sync_with_stdio(0);
cin.tie(0);
cout.tie(0);
cin>>n>>m>>r>>mod;
memset(h,-1,sizeof h);
for(int i=1;i<=n;i++)
cin>>w[i];
for(int i=1;i<n;i++)
{
int u,v;
cin>>u>>v;
add(u,v);
add(v,u);
}
dfs1(r,0,1); //根节点,父亲,深度
dfs2(r,r);
build(1,1,n); //用新点权建立线段树
while(m--)
{
int op,x,y,z;
cin>>op;
if(op==1)
{
cin>>x>>y>>z;
updrange(x,y,z);
}
else if(op==2)
{
cin>>x>>y;
cout<<qrange(x,y)<<endl;
}
else if(op==3)
{
cin>>x>>z;
upson(x,z);
}
else if(op==4)
{
cin>>x;
cout<<qson(x)<<endl;
}
}
return 0;
}
by xuhaotian @ 2024-07-10 16:13:09
@YGW6 push_down出问题了
by xuhaotian @ 2024-07-10 16:13:55
算左右儿子的区间长度那块错了
by YGW6 @ 2024-07-10 16:20:41
@xuhaotian
dalao麻烦再问一下哪里错了?没看出来啊
by xuhaotian @ 2024-07-10 16:26:50
应该用左右区间端点算长度,直接用父亲的len/2是假的
by xuhaotian @ 2024-07-10 16:27:52
@YGW6
cpp
void push_down(int u,int l,int r) //下放lazy标记
{
lazy[2*u]+=lazy[u];
lazy[2*u+1]+=lazy[u];
int mid=l+r/2;
sum[2*u]+=lazy[u]*(mid-l+1);
sum[2*u]%=mod;
sum[2*u+1]+=lazy[u]*(r-mid);
sum[2*u+1]%=mod;
lazy[u]=0;
}
改成这样就可以了
by YGW6 @ 2024-07-10 16:34:55
@xuhaotian
谢谢dalao,麻烦了,以关注
by YGW6 @ 2024-07-10 16:36:06
不过那个len/2算出来是会比正常的值少0.5是吗?
by chenzhiyv @ 2024-07-10 16:39:36
你代码中,len=r-l+1,并且你在算左儿子时直接用len-len/2,将len=r-l+1带入,可以算出左儿子的区间为0.5r-0.5l+0.5,但正确的左儿子区间应为mid-l,mid=(l+r)/2 带入算出有正确的左儿子区间是0.5r-0.5l+1,所以错了,右儿子同理
by chenzhiyv @ 2024-07-10 16:40:12
但我不确定加上0.5会不会对
by YGW6 @ 2024-07-10 16:44:53
@chenzhiyv
行,谢谢你