求助!关于建树部分的疑问

P3384 【模板】重链剖分/树链剖分

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 哦哦哦 原来如此!谢谢大佬!


|