leo12334 @ 2024-07-08 08:19:44
在调试的时候发现一个很神奇的问题,
void build(int p,int l,int r){
t[p].l=l;t[p].r=r;
t[p].len=r-l+1;t[p].flag=0;
if(l==r){t[p].v=a[b[l]];return;}
mid=(l+r)>>1;cout<<l<<' '<<r<<' '<<mid<<endl;
build(p*2,l,mid);
build(p*2+1,mid+1,r);
t[p].v=(t[p*2].v+t[p*2+1].v)%mod;
}
这一段代码不正确,会出现1 3,1 2,2 3这种重复计算的情况,
void build(int p,int l,int r){
t[p].l=l;t[p].r=r;
int mid=(l+r)/2;t[p].flag=0;
t[p].len=r-l+1;
// cout<<l<<' '<<r<<' '<<mid<<endl;
if(l==r){t[p].v=a[b[l]];return ;}
build(p*2,l,mid);
build(p*2+1,mid+1,r);
t[p].v=(t[p*2].v+t[p*2+1].v)%mod;
}
而这一段就是正确的。蒟蒻的我百思不得其解,求助各位大佬帮助
下面是ac的代码
#include<bits/stdc++.h>
using namespace std;
#define N 500860
#define ll long long
#define in read()
ll a[N],b[N],mod;
int fa[N],n,m,dfn[N],cnt,x,y,z,v,l,r,mid,root,op,deep[N],head[N],tp[N],size[N],son[N],tt;
struct node{
int next,to;
}e[N*2];
struct tree{
int l,r,len;
ll v,flag;
}t[N*4];
void down(int p){
if(t[p].flag==0)return;
ll v=t[p].flag;
t[p*2].v+=v*t[p*2].len; t[p*2].v%=mod;
t[p*2+1].v+=v*t[p*2+1].len;t[p*2+1].v%=mod;
t[p*2].flag+=v; t[p*2+1].flag+=v;
t[p*2].flag%=mod;t[p*2+1].flag%=mod;
t[p].flag=0;
}
void add(int x,int y){
e[++cnt].next=head[x];
e[cnt].to=y;
head[x]=cnt;
}
ll read(){
ll x=0,f=1;char c=getchar();
while(c<'0'||c>'9'){
if(c=='-')f=-1;c=getchar();
}
while(c<='9'&&c>='0'){
x=(x<<3)+(x<<1)+c-'0';
c=getchar();
}
return x*f;
}
void dfs1(int x){
size[x]=1;
int big=0;
for(int i=head[x];i;i=e[i].next){
int y=e[i].to;
if(y==fa[x])continue;
fa[y]=x;deep[y]=deep[x]+1;
dfs1(y);
size[x]+=size[y];
if(size[y]>big)big=size[y],son[x]=y;
}
}
void dfs2(int x,int tou){
dfn[x]=++tt;
b[tt]=x;
tp[x]=tou;
if(son[x]) dfs2(son[x],tou);
for(int i=head[x];i;i=e[i].next){
int y=e[i].to;
if(y!=fa[x]&&y!=son[x]){
dfs2(y,y);
}
}
}
//void build(int p,int l,int r){
// t[p].l=l;t[p].r=r;
// t[p].len=r-l+1;t[p].flag=0;
// if(l==r){t[p].v=a[b[l]];return;}
// mid=(l+r)>>1;cout<<l<<' '<<r<<' '<<mid<<endl;
// build(p*2,l,mid);
// build(p*2+1,mid+1,r);
// t[p].v=(t[p*2].v+t[p*2+1].v)%mod;
//}
void build(int p,int l,int r){
t[p].l=l;t[p].r=r;
int mid=(l+r)/2;t[p].flag=0;
t[p].len=r-l+1;
// cout<<l<<' '<<r<<' '<<mid<<endl;
if(l==r){t[p].v=a[b[l]];return ;}
build(p*2,l,mid);
build(p*2+1,mid+1,r);
t[p].v=(t[p*2].v+t[p*2+1].v)%mod;
}
void add(int p,int l,int r,int v){
if(l>t[p].r||r<t[p].l)return;
else if(l<=t[p].l&&r>=t[p].r) {
t[p].v+=t[p].len*v;t[p].v%=mod;
t[p].flag+=v; t[p].flag%=mod;
}
else{
down(p);
add(p*2,l,r,v);add(p*2+1,l,r,v);
t[p].v=(t[p*2].v+t[p*2+1].v)%mod;
}
}
ll query(int p,int l,int r){
if(l>t[p].r||r<t[p].l)return 0;
else if(l<=t[p].l&&r>=t[p].r) return t[p].v;
else{
down(p);
return query(p*2,l,r)+query(p*2+1,l,r);
}
}
void op1(int x,int y,int z){
while(tp[x]!=tp[y]){
if(deep[tp[x]]>deep[tp[y]])swap(x,y);
add(1,dfn[tp[y]],dfn[y],z);
y=fa[tp[y]];
}
if(deep[x]>deep[y])swap(x,y);
add(1,dfn[x],dfn[y],z);
}
void op2(int x,int y){
ll ans=0;
while(tp[x]!=tp[y]){
if(deep[tp[x]]>deep[tp[y]])swap(x,y);
ans+=query(1,dfn[tp[y]],dfn[y]);ans%=mod;
y=fa[tp[y]];
}
if(deep[x]>deep[y])swap(x,y);
ans+=query(1,dfn[x],dfn[y]);
cout<<ans%mod<<endl;
}
void op3(int x,int z){
add(1,dfn[x],dfn[x]+size[x]-1,z);
}
void op4(int x){
cout<<query(1,dfn[x],dfn[x]+size[x]-1)%mod<<endl;
}
int main(){
n=in,m=in,root=in,mod=in;
for(int i=1;i<=n;i++) a[i]=in;
for(int i=1;i<n;i++){
x=in,y=in;
add(x,y);add(y,x);
}
dfs1(root);
dfs2(root,root);
build(1,1,n);
while(m--){
op=in;
if(op==1){ x=in,y=in,z=in;op1(x,y,z);}
else if(op==2){ x=in,y=in;op2(x,y);}
else if(op==3){ x=in,y=in;op3(x,y);}
else{ x=in;op4(x);}
}
return 0;
}
by qzmoot @ 2024-07-08 09:03:45
@leo12334 这两个代码一模一样欸
by leo12334 @ 2024-07-08 09:15:14
@qzmoot 对呀 没看出来哪里不一样QAQ
by qzmoot @ 2024-07-08 09:17:27
@leo12334 你单点调试试一下
by qzmoot @ 2024-07-08 09:18:17
@leo12334 或者一步步把错误代码改成正确代码,在步骤中输出答案,看哪里变成正确
by sdyzpf @ 2024-07-08 09:31:24
错误代码:
void build(int p,int l,int r){
t[p].l=l;t[p].r=r;
t[p].len=r-l+1;t[p].flag=0;
if(l==r){t[p].v=a[b[l]];return;}
mid=(l+r)>>1;
build(p*2,l,mid);
build(p*2+1,mid+1,r);
t[p].v=(t[p*2].v+t[p*2+1].v)%mod;
}
正确代码:
void build(int p,int l,int r){
t[p].l=l;t[p].r=r;
t[p].len=r-l+1;t[p].flag=0;
if(l==r){t[p].v=a[b[l]];return;}
int mid=(l+r)>>1;
build(p*2,l,mid);
build(p*2+1,mid+1,r);
t[p].v=(t[p*2].v+t[p*2+1].v)%mod;
}
by sdyzpf @ 2024-07-08 09:32:20
@leo12334 你的mid是全局变量,递归进入第一个build的时候会改变mid的值,影响第二个build的左端点mid+1
by leo12334 @ 2024-07-08 10:50:55
@sdyzpf 哦哦哦 原来如此!谢谢大佬!