树剖写挂了,求助。

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

hamster000 @ 2024-02-16 22:48:26

#include <bits/stdc++.h>
using namespace std;
const int maxn=1e5+10;
int mod,dep[maxn],dfn[maxn],rnk[maxn],siz[maxn],fa[maxn],top[maxn],son[maxn];
int w[maxn],wt[maxn];
vector <int> vec[maxn];
void dfs(int u,int f){
    siz[u]=1;fa[u]=f,dep[u]=dep[f]+1;
    for(auto to:vec[u]){
        if(to==f) continue;
        dfs(to,u);
        siz[u]+=siz[to];
        if(siz[to]>siz[son[u]]){
            son[u]=to;
        }
    }
}
int cnt=0;
void dfs2(int u,int tp){
    top[u]=tp,dfn[u]=++cnt,rnk[cnt]=u;
    wt[cnt]=w[u];
    if(!son[u]) return ;
    dfs2(son[u],tp);
    for(auto to:vec[u]){
        if(to==fa[u]||to==son[u]) continue;
        dfs2(to,to);
    }
}
#define lc 2*rt
#define rc 2*rt+1
int val[4*maxn],lazy[4*maxn],le[maxn*4],ri[maxn*4];
void pushup(int rt){
    val[rt]=(val[lc]+val[rc])%mod;
    return ;
}
void pushdown(int rt){
    if(!lazy[rt]) return ;
    lazy[lc]+=lazy[rt];
    lazy[rc]+=lazy[rt];
    val[lc]+=lazy[rt]*(ri[lc]-le[lc]+1);
    val[rc]+=lazy[rt]*(ri[rc]-le[rc]+1);
    lazy[rt]=0;
}
void build(int rt,int l,int r){
    le[rt]=l,ri[rt]=r;
    if(l==r){
        val[rt]=wt[l];
    }else{
        int mid=(l+r) >> 1;
        build(lc,l,mid);
        build(rc,mid+1,r);
        pushup(rt);
    }
}
long long res;
void query_sum(int rt,int x,int y){
    int l=le[rt],r=ri[rt];
    if(x<=l&&r<=y){
        res+=val[rt];
        res%=mod;
        return ;
    }
    int mid=(l+r)/2;
    pushdown(rt);
    if(x<=mid){
        query_sum(lc,x,y);
    }if(y>mid){
        query_sum(rc,x,y);
    }
}
//x,y:修改区间
void update(int rt,int x,int y,int k){
    int l=le[rt],r=ri[rt];
    if(x<=l&&r<=y){
        val[rt]+=k*(r-l+1);
        lazy[rt]+=k;
    }else{
        pushdown(rt);
        int mid=(l+r)/2;
        if(x<=mid) update(lc,x,y,k);
        if(r>mid) update(rc,x,y,k);
        pushup(rt);
    }
}

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);
        res=0;
        query_sum(1,dfn[top[x]],dfn[x]);
        ans+=res;
        ans%=mod;
        x=fa[top[x]];
    }
    if(dep[x]>dep[y]) swap(x,y);
    res=0;
    query_sum(1,dfn[x],dfn[y]);
    ans+=res;
    return ans%mod;
}

int querySon(int rt){
    res=0;
    query_sum(1,dfn[rt],dfn[rt]+siz[rt]-1);
    return res;
}

void updateRange(int x,int y,int k){
    k%=mod;
    while(top[x]!=top[y]){
        if(dep[top[x]]<dep[top[y]]) swap(x,y);
        update(1,dfn[top[x]],dfn[x],k);
        x=fa[top[x]];
    }
    if(dep[x]>dep[y]) swap(x,y);
    update(1,dfn[x],dfn[y],k);
}

void updateSon(int x,int k){
    update(1,dfn[x],dfn[x]+siz[x]-1,k);
}

int main(){
    int n,m,r,p;
    cin >> n >> m >> r >> p;
    mod=p;
    for(int i=1;i<=n;i++){
        cin >> w[i];
    }
    for(int i=1;i<n;i++){
        int a,b;
        cin >> a >> b;
        vec[a].push_back(b);
        vec[b].push_back(a);
    }
    dfs(r,0);
    dfs2(r,r);
    build(1,1,n);
    while(m--){
        int opt,x,y,z;
        cin >> opt;
        if(opt==1){
            cin >> x >> y >> z;
            updateRange(x,y,z);
        }if(opt==2){
            cin >> x >> y;
            cout << query_Range(x,y) << endl;
        }if(opt==3){
            cin >> x >> z;
            updateSon(x,z);
        }if(opt==4){
            cin >> x;
            cout << querySon(x) << endl;
        }
    }
}

样例都没过,请大佬帮忙找找问题。


by hamster000 @ 2024-02-16 22:58:47

抱歉耽误各位时间。问题已经解决。 问题出在代码81行

if(r>mid) update(rc,x,y,k);

应为

if(y>mid) update(rc,x,y,k);

总结:线段树出现错误,没有搞清楚什么是需要update的东西。警钟长鸣。

修改之后可以通过三个点,仍然有一定问题,请各位指出。


by 142857tree @ 2024-02-16 23:06:33

query_range 第三行


by hamster000 @ 2024-02-16 23:07:16

成功定位问题在第86行 query_Range函数(计算一条链上的和)。 错误发现在89行。

if(dep[top[x]]!=dep[top[y]]) swap(x,y);

应为

if(dep[top[x]]<dep[top[y]]) swap(x,y);

原因:一条链上的答案之和可以被多次跳重链到它们的 lca(x,y) 上计算,答案就是 xlca(x,y) 上所有点的点权和加上 ylca(x,y) 的点权和减去 lca(x,y) 的点权,故必须每次跳小的链直到 x,y 在同一重链上。

提交之后能够得到满分


|