蒟蒻树链剖分模板WA求调

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

liaoz123 @ 2023-01-11 09:35:37

昨天刚学树链剖分,写代码WA0分,但是第一个数据点下下来输出完全正确,把代码分开以后线段树模板可以过,树链剖分LCA可以过,但合起来就过不了qwq。样例也可以过。调了两小时调了个寂寞……大佬求调


by liaoz123 @ 2023-01-11 09:36:00

代码如下

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=2e5+5;
struct node{
    int nxt,to;
    ll dis;
}e[N];
//id表示dfs序,top表示链顶,siz表示子树大小,son表示重儿子编号,f表示父亲编号
//num表示边数,ww表示原节点值,w表示线段树上的值,s为线段树 
int num,head[N],top[N],f[N],dep[N],siz[N],id[N],cnt,son[N];
ll s[N<<2],tag[N<<2],mod,ww[N],w[N];
void add(int x,int y){
    e[++num].to=y;
    e[num].nxt=head[x];
    head[x]=num;
}
int n,m,r;//树链剖分部分 
void dfs1(int u,int fa){
    f[u]=fa;
    dep[u]=dep[fa]+1;
    siz[u]=1;
    for(int i=head[u];i;i=e[i].nxt){
        int v=e[i].to;
        if(v==fa)continue;
        dfs1(v,u);
        siz[u]+=siz[v];
        if(!son[u]||siz[v]>siz[son[u]])
        son[u]=v;
    }
}
void dfs2(int u,int val){
    top[u]=val;
    id[u]=++cnt;
    w[cnt]=ww[u];
    if(!son[u])return;
    dfs2(son[u],val);
    for(int i=head[u];i;i=e[i].nxt){
        int v=e[i].to;
        if(v!=son[u]&&v!=f[u])dfs2(v,v);
    }
}
void pushup(int k){//合并 
    s[k]=(s[k*2]+s[k*2+1])%mod;
}
void addtag(int k,int l,int r,ll val){//懒标记下传 
    s[k]=(s[k]+ll(r-l+1)*val)%mod;
    tag[k]+=val;tag[k]%mod;
}
void pushdown(int k,int l,int r){ 
    int mid=(l+r)>>1;
    addtag(k*2,l,mid,tag[k]);
    addtag(k*2+1,mid+1,r,tag[k]);
    tag[k]=0;
}
void build(int k,int l,int r){//建树 
    if(l==r){
        s[k]=w[l];
        return;
    }
    int mid=(l+r)>>1;
    build(k*2,l,mid);
    build(k*2+1,mid+1,r);
    pushup(k);
}
ll query(int k,int l,int r,int x,int y){//线段树询问 
    if(l>y||r<x)return 0;
    if(l>=x&&r<=y)return s[k]%mod;
    int mid=(l+r)>>1;
    pushdown(k,l,r);
    return (query(k*2,l,mid,x,y)+query(k*2+1,mid+1,r,x,y))%mod;
}
void change(int k,int l,int r,int x,int y,ll val){//线段树改变 
    if(l>y||r<x)return;
    if(l>=x&&r<=y){
        addtag(k,l,r,val);
        return;
    }
    int mid=(l+r)>>1;
    pushdown(k,l,r);
    change(k*2,l,mid,x,y,val);
    change(k*2+1,mid+1,r,x,y,val);
    pushup(k);
}
void update_range(int x,int y,ll val){//路径add 
    ll ans=0;
    while(top[x]!=top[y]){
        if(dep[top[x]]<dep[top[y]])swap(x,y);
        change(1,1,n,id[top[x]],id[x],val);
        x=f[top[x]];
    }
    if(dep[x]>dep[y])swap(x,y);
    change(1,1,n,id[x],id[y],val);
}
ll query_range(int x,int y){//路径求和 
    ll ans=0;
    while(top[x]!=top[y]){
        if(dep[top[x]]<dep[top[y]])swap(x,y);
        ans=(ans+query(1,1,n,id[x],id[top[x]]))%mod;
        x=f[top[x]];
    }
    if(dep[x]>dep[y])swap(x,y);
    ans=(ans+query(1,1,n,id[x],id[y]))%mod;
}
void update_tree(int x,ll val){change(1,1,n,id[x],id[x]+siz[x]-1,val);}//子树改变 
ll query_tree(int x){return query(1,1,n,id[x],id[x]+siz[x]-1);}//子树求和 
int main(){
    //freopen("P3384_1.in","r",stdin);
    scanf("%d%d%d%lld",&n,&m,&r,&mod);
    for(int i=1;i<=n;i++)scanf("%lld",&ww[i]);
    for(int i=1,x,y;i<n;i++){
        scanf("%d%d",&x,&y);
        add(x,y),add(y,x);
    }
    dfs1(r,0);
    dfs2(r,r);
    build(1,1,n);
    while(m--){
        int op,x;ll y,z;
        scanf("%d",&op);
        switch(op){
            case 1:scanf("%d%d%lld",&x,&y,&z);update_range(x,y,z);break;
            case 2:scanf("%d%d",&x,&y);printf("%lld\n",query_range(x,y));break;
            case 3:scanf("%d%lld",&x,&y);update_tree(x,y);break;
            case 4:scanf("%d",&x);printf("%lld\n",query_tree(x));break;
        }
    }
    return 0;
}

by liaoz123 @ 2023-01-11 10:08:48

已AC,谢谢大家


|