stickman_stickmin @ 2024-06-26 18:22:53
如标题,已经查了很久步步取模,查逻辑也感觉没问题 代码:
#include<bits/stdc++.h>
using namespace std;
const int N=1e5+10;
struct tree{
long long val,l,r,add;
}t[4*N+10];
long long n,m,s,mod;
long long w[N],w_new[N];
int ls(int p){return p<<1;}
int rs(int p){return p<<1|1;}
void addtag(int p,int d){
t[p].add+=d;
t[p].val+=d*(t[p].r-t[p].l+1);
t[p].val%=mod;
}
void push_up(int p){
t[p].val=t[ls(p)].val+t[rs(p)].val;
t[p].val%=mod;
}
void push_down(int p){//下传标记
if(t[p].add){
addtag(ls(p),t[p].add);
addtag(rs(p),t[p].add);
t[p].add=0;
}
}
void build(int p,int l,int r){
t[p].l=l,t[p].r=r;
if(l==r){
t[p].val=w_new[l];//依照树的dfn序建树,而非原序列
t[p].val%=mod;
return;
}
int mid=(t[p].l+t[p].r)>>1;
build(p*2,l,mid);
build(p*2+1,mid+1,r);
push_up(p);
}
void update(int p,int l,int r,int k){//线段树区间求和 p=1
if(l<=t[p].l && r>=t[p].r){
addtag(p,k);
return;
}
push_down(p);
int mid=(t[p].l+t[p].r)>>1;
if(l<=mid)update(ls(p),l,r,k);
if(r>mid)update(rs(p),l,r,k);
push_up(p);
}
int query(int p,int l,int r){//线段树区间求和 p=1
if(l<=t[p].l && r>=t[p].r){
return t[p].val%=mod;
}
push_down(p);
int ans=0;
int mid=(t[p].l+t[p].r)>>1;
if(l<=mid)ans+=query(ls(p),l,r);
if(r>mid)ans+=query(rs(p),l,r);
return ans;//后面用到ans时在后面取模
}
struct node{
int to,nxt;
}edge[2*N];//无向图,边x2
int cnt,head[N*2];
void prework(){
for(int i=0;i<N*2;i++){
head[i]=-1;edge[i].nxt=-1;
}
cnt=0;
}
void adg(int u,int v){
edge[cnt].to=v,edge[cnt].nxt=head[u],head[u]=cnt++;
}
int dep[N],siz[N],son[N],top[N],fat[N],id[N];
int num=0;
void dfs1(int u,int fa){//收集链上有关数据
dep[u]=dep[fa]+1;
fat[u]=fa;
siz[u]=1;
for(int i=head[u];~i;i=edge[i].nxt){
int v=edge[i].to;
if(v!=fa){
fat[v]=u;
dfs1(v,u);
siz[u]+=siz[v];//回溯后,将v的儿子数加到u上
if(!son[u]||siz[son[u]]<siz[v])//标记每个非叶子的重节点
son[u]=v;
}
}
}
void dfs2(int x,int topx){//根据数据进一步得出另一些数据
id[x]=++num;
w_new[num]=w[x];//把每个节点初始值赋给新节点
top[x]=topx;//u所在链头
if(!son[x])return;//u是叶子,无儿子,返回
dfs2(son[x],topx);//优先dfs重儿子
for(int i=head[x];~i;i=edge[i].nxt){
int v=edge[i].to;
if(v!=fat[x] && v!=son[x]){
//无向图父亲显然不行 重儿子已经整过了
dfs2(v,v);//每个轻儿子都有 以他为头 的重链
}
}
}
void update_range(int x,int y,int z){//节点最短路径上节点赋值
while(top[x]!=top[y]){//不在同一条链
if(dep[top[x]]<dep[top[y]])swap(x,y);//以x为操作对象,要求x所在链的顶更深
update(1,id[top[x]],id[x],z);
x=fat[top[x]];
}
if(dep[x]>dep[y])swap(x,y);//循环结束,x,y在同一链上
update(1,id[x],id[y],z);
}
int query_range(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,id[x],id[top[x]]);
ans%=mod;
x=fat[top[x]];
}
if(dep[x]>dep[y])swap(x,y);//若LCA=y,则交换x,y使得x更浅,使得id[x]<=id[y]
ans+=query(1,id[x],id[y]);
return ans%mod;
}
void update_tree(int x,int k){//x子树节点赋值
update(1,id[x],id[x]+siz[x]-1,k);
}
int query_tree(int x){//x子树节点和
return query(1,id[x],id[x]+siz[x]-1)%mod;
}
signed main(){
prework();
cin>>n>>m>>s>>mod;
for(int i=1;i<=n;i++)cin>>w[i];
for(int i=1;i<=n-1;i++){
int u,v;
cin>>u>>v;
adg(u,v);
adg(v,u);
}
dfs1(s,0);
dfs2(s,s);
build(1,1,n);
while(m--){
int op,x,y,z;
cin>>op;
switch(op){
case 1:
cin>>x>>y>>z;
update_range(x,y,z);
break;
case 2:
cin>>x>>y;
cout<<query_range(x,y)<<'\n';
break;
case 3:
cin>>x>>z;
update_tree(x,z);
break;
case 4:
cin>>x;
cout<<query_tree(x)<<'\n';
break;
}
}
return 0;
}
by stickman_stickmin @ 2024-06-27 18:22:02
此贴已结,
line120
应当为
ans+=query(1,id[top[x]],id[x]);
id[top[x]]在树中的dfn序在id[x]前面
by oliver326 @ 2024-07-04 20:25:02
哇哇哇,谢谢巨佬提醒!写的时候不动脑子全弄反了:(
by newtocpp @ 2024-08-10 18:36:19
%%%