树链剖分 37 pts 求助(悬关)

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

w9095 @ 2024-01-12 18:40:42

#include <bits/stdc++.h>
using namespace std;
struct edge
{
    long long v,nxt;
}e[800000];
struct node
{
    long long l,r,v,ad;
}tr[800000];
long long n,m,r,mod,op,x,y,z,a[300000],c[300000],h[300000],cnt=0,root=0;
long long lc[800000],rc[800000];
long long dep[300000],fa[300000],siz[300000],hs[300000],id[300000],top[300000],tol=0;
void add_edge(long long u,long long v)
{
    e[++cnt].nxt=h[u];
    e[cnt].v=v;
    h[u]=cnt;
}

void pushup(long long x)
{
    tr[x].v=(tr[lc[x]].v+tr[rc[x]].v)%mod;
}

void pushdown(long long x)
{
    tr[x].v=(tr[x].v+tr[x].ad*(tr[x].r-tr[x].l+1)%mod)%mod;
    tr[lc[x]].ad=(tr[lc[x]].ad+tr[x].ad)%mod,tr[rc[x]].ad=(tr[rc[x]].ad+tr[x].ad)%mod,tr[x].ad=0;
}

void build(long long now,long long l,long long r)
{
    tr[now].l=l,tr[now].r=r;
    lc[now]=now*2,rc[now]=now*2+1;
    if(l==r)
       {
        tr[now].v=a[l]%mod;
        return;
       }
    long long mid=(l+r)/2;
    build(lc[now],l,mid),build(rc[now],mid+1,r);
    pushup(now);
}

void add(long long now,long long l,long long r,long long k)
{
    pushdown(now);
    if(tr[now].l>=l&&tr[now].r<=r)
       {
        tr[now].ad+=k;
        return;
       }
    long long mid=(tr[now].l+tr[now].r)/2;
    if(l<=mid)add(lc[now],l,r,k);
    if(r>=mid+1)add(rc[now],l,r,k);
    pushdown(lc[now]);pushdown(rc[now]);
    pushup(now);
}

long long query(long long now,long long l,long long r)
{
    pushdown(now);
    long long ans=0;
    if(tr[now].l>=l&&tr[now].r<=r)return tr[now].v;
    long long mid=(tr[now].l+tr[now].r)/2;
    if(l<=mid)ans+=query(lc[now],l,r);
    if(r>=mid+1)ans+=query(rc[now],l,r);
    return ans;
}

void dfs1(long long x,long long f)
{
    long long mx=0,ans=0;
    dep[x]=dep[f]+1,fa[x]=f,siz[x]=1;
    for(int i=h[x];i;i=e[i].nxt)
        if(e[i].v!=f)
            {
                dfs1(e[i].v,x);
                if(siz[e[i].v]>ans)mx=siz[e[i].v],ans=e[i].v;
                siz[x]+=siz[e[i].v];
            }
    hs[x]=ans;
}

void dfs2(long long x,long long f,long long tf)
{
    id[x]=++tol,a[id[x]]=c[x],top[x]=tf;
    if(hs[x]!=0)dfs2(hs[x],x,tf);
    for(int i=h[x];i;i=e[i].nxt)
        if(e[i].v!=f&&e[i].v!=hs[x])dfs2(e[i].v,x,e[i].v);
}

void radd(long long x,long long y,long long z)
{
    while(top[x]!=top[y])
       {
       if(dep[top[x]]>dep[top[y]])swap(x,y);
       add(root,id[top[y]],id[y],z);
       y=fa[top[y]];
       }
    if(dep[x]>dep[y])swap(x,y);
    add(root,id[x],id[y],z);
}

long long rquery(long long x,long long y)
{
    long long ans=0;
    while(top[x]!=top[y])
       {
       if(dep[top[x]]>dep[top[y]])swap(x,y);
       ans=(ans+query(root,id[top[y]],id[y]))%mod;
       y=fa[top[y]];
       }
    if(dep[x]>dep[y])swap(x,y);
    ans=(ans+query(root,id[x],id[y]))%mod;
    return ans;
}

void sadd(long long x,long long z)
{
    add(root,id[x],id[x]+siz[x]-1,z);
}

long long squery(long long x)
{
    return query(root,id[x],id[x]+siz[x]-1);
}

int main()
{
    scanf("%lld%lld%lld%lld",&n,&m,&r,&mod);
    for(int i=1;i<=n;i++)scanf("%lld",&c[i]);
    for(int i=1;i<=n-1;i++)
        {
            scanf("%lld%lld",&x,&y);
            add_edge(x,y),add_edge(y,x);
        }
    dfs1(r,0),dfs2(r,0,0),n=tol,root=1;
    build(root,1,n);
    for(int i=1;i<=m;i++)
        {
            scanf("%lld",&op);
            if(op==1)
               {
               scanf("%lld%lld%lld",&x,&y,&z);
               radd(x,y,z);
               }
            else if(op==2)
               {
                scanf("%lld%lld",&x,&y);
                printf("%lld\n",rquery(x,y));
               }
            else if(op==3)
               {
                scanf("%lld%lld",&x,&z);
                sadd(x,z);
               }
            else if(op==4)
               {
                scanf("%lld",&x);
                printf("%lld\n",squery(x));
               }
        }
    return 0;
}

目测线段树应该是对的,不仅有 WA,还有 TLE。


by w9095 @ 2024-01-12 18:51:39

@w9095 现在 73 pts 了,有 3 个 TLE。


by w9095 @ 2024-01-12 19:13:35

@w9095 破案了,这一行:

if(siz[e[i].v]>ans)mx=siz[e[i].v],ans=e[i].v;

应该改为:

if(siz[e[i].v]>mx)mx=siz[e[i].v],ans=e[i].v;

已 AC,此帖结


|