37分树剖求调

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

FJ_OIer @ 2024-09-02 22:36:03

马蜂清爽

#include <bits/stdc++.h>
#define int long long
using namespace std;
int n,m,r,p,u,v,op,k,cnt;
int a[100001],fa[100001],dep[100001],siz[100001],w[100001];
int top[100001],dfn[100001];
int sum[1000001],tag[1000001];
vector<int> e[100001];
void dfs1(int u){
    siz[u]=1;
    dfn[u]=++cnt;
    w[cnt]=a[u];
    for (int v:e[u]){
        if (v==fa[u]){
            continue;
        }
        dep[v]=dep[u]+1;
        fa[v]=u;
        dfs1(v);
        siz[u]+=siz[v];
    }
}
void dfs2(int u,int t){
    int p=0;
    top[u]=t;
    for (int v:e[u]){
        if (v==fa[u]){
            continue;
        }
        if (siz[v]>siz[p]){
            p=v;
        }
    }
    if (!p){
        return;
    }
    dfs2(p,t);
    for (int v:e[u]){
        if (v==fa[u]||v==p){
            continue;
        }
        dfs2(v,v);
    }
}
void pushdown(int l,int r,int mid,int k){
    tag[k<<1]+=tag[k];
    tag[k<<1|1]+=tag[k];
    sum[k<<1]+=tag[k]*(mid-l+1);
    sum[k<<1|1]+=tag[k]*(r-mid);
    tag[k<<1]%=p;
    tag[k<<1|1]%=p;
    sum[k<<1]%=p;
    sum[k<<1|1]%=p;
    tag[k]=0;
}
void modify(int l,int r,int k,int a,int b,int m){
    if (r<a||l>b){
        return;
    }
    if (l>=a&&r<=b){
        tag[k]+=m;
        sum[k]+=m*(r-l+1);
        tag[k]%=p;
        sum[k]%=p;
        return;
    }
    int mid=(l+r)>>1;
    pushdown(l,r,mid,k);
    modify(l,mid,k<<1,a,b,m);
    modify(mid+1,r,k<<1|1,a,b,m);
    sum[k]=(sum[k<<1]+sum[k<<1|1])%p;
}
int query(int l,int r,int k,int a,int b){
    if (l>b||r<a){
        return 0;
    }
    if (l>=a&&r<=b){
        return sum[k];
    }
    int mid=(l+r)>>1;
    pushdown(l,r,mid,k);
    return (query(l,mid,k<<1,a,b)+query(mid+1,r,k<<1|1,a,b))%p;
}
void build(int l,int r,int k){
    if (l==r){
        sum[k]=w[l]%p;
        return;
    }
    int mid=(l+r)>>1;
    build(l,mid,k<<1);
    build(mid+1,r,k<<1|1);
    sum[k]=(sum[k<<1]+sum[k<<1|1])%p;
}
void add(int u,int v,int k){
    while (top[u]!=top[v]){
        if (dep[v]>dep[u]){
            swap(u,v);
        }
        modify(1,n,1,dfn[top[u]],dfn[u],k);
        u=fa[top[u]];
    }
    if (dep[v]>dep[u]){
        swap(u,v);
    }
    modify(1,n,1,dfn[v],dfn[u],k);
}
int qry(int u,int v){
    int ans=0;
    while (top[u]!=top[v]){
        if (dep[v]>dep[u]){
            swap(u,v);
        }
        ans=(ans+query(1,n,1,dfn[top[u]],dfn[u]))%p;
        u=fa[top[u]];
    }
    if (dep[v]>dep[u]){
        swap(u,v);
    }
    ans=(ans+query(1,n,1,dfn[v],dfn[u]))%p;
    return ans;
}
signed main(){
    cin>>n>>m>>r>>p;
    for (int i=1;i<=n;i++){
        cin>>a[i];
    }
    for (int i=1;i<n;i++){
        cin>>u>>v;
        e[u].push_back(v);
        e[v].push_back(u);
    }
    dfs1(r);
    dfs2(r,r);
    build(1,n,1);
    while (m--){
        cin>>op>>u;
        if (op==1){
            cin>>v>>k;
            add(u,v,k);
        }else if (op==2){
            cin>>v;
            cout<<qry(u,v)<<endl;
        }else if (op==3){
            cin>>k;
            modify(1,n,1,dfn[u],dfn[u]+siz[u]-1,k);
        }else{
            cout<<query(1,n,1,dfn[u],dfn[u]+siz[u]-1)<<endl;
        }
    }
    return 0;
}

by CarlosProvo @ 2024-09-02 22:52:33

你的dfs1和dfs2写得好怪,功能是混的

void dfs1(int u,int father,int depth)
{
    dep[u]=depth,fa[u]=father,sz[u]=1;
    for(int i=h[u];i!=-1;i=e[i].ne)
    {
        int v=e[i].to;
        if(v==father)continue;
        dfs1(v,u,depth+1);
        sz[u]+=sz[v];
        if(sz[son[u]]<sz[v])son[u]=v;
    }
}
void dfs2(int u,int t)
{
    id[u]=++cnt,pw[cnt]=lw[u],top[u]=t;
    if(!son[u])return ;
    dfs2(son[u],t);
    for(int i=h[u];i!=-1;i=e[i].ne)
    {
        int v=e[i].to;
        if(v==fa[u]||v==son[u])continue;
        dfs2(v,v);
    }
}

这是我的dfs1&dfs2的函数

dfs1(R,-1,1);
dfs2(R,R);

这是我的传参虽然没什么参考价值


by endswitch @ 2024-09-02 22:57:19

@CSP_juruo 应该是在 dfs1 里面就把重儿子求出来了吧。


by FJ_OIer @ 2024-09-02 23:08:29

@endswitch 这个东西我放在dfs2里多写了一个循环

虽然没啥用但应该是正确的


by CarlosProvo @ 2024-09-02 23:08:32

@endswitch 是的捏 (^__^)


by Luo_Saisei @ 2024-09-02 23:29:31

@CSP_juruo 树链剖分要比较链顶高度 所以query和add部分写错了


by FJ_OIer @ 2024-09-03 12:27:40

@gcomplex 但这样仍是37:

void add(int u,int v,int k){
    while (top[u]!=top[v]){
        if (dep[top[v]]>dep[top[u]]){
            swap(u,v);
        }
        modify(1,n,1,dfn[top[u]],dfn[u],k);
        u=fa[top[u]];
    }
    if (dep[v]>dep[u]){
        swap(u,v);
    }
    modify(1,n,1,dfn[v],dfn[u],k);
}
int qry(int u,int v){
    int ans=0;
    while (top[u]!=top[v]){
        if (dep[top[v]]>dep[top[u]]){
            swap(u,v);
        }
        ans=(ans+query(1,n,1,dfn[top[u]],dfn[u]))%p;
        u=fa[top[u]];
    }
    if (dep[v]>dep[u]){
        swap(u,v);
    }
    ans=(ans+query(1,n,1,dfn[v],dfn[u]))%p;
    return ans;
}

|