95RE,救救孩子……

P1600 [NOIP2016 提高组] 天天爱跑步

hanmo0321 @ 2020-11-03 17:22:17

#include<bits/stdc++.h>
using namespace std;
int n,m,edgenum,vet[600000],Next[600000],head[300000],dep[300000],Log[300000],f[300000][20];
int U[300000],V[300000],LCA[300005],in[300005],out[300005],dfs_clock,maxd,num,rt[300005];
int tree[10000005],ls[10000005],rs[10000005],t[300000],ans[300005];
void addedge(int u,int v){
    vet[++edgenum]=v;
    Next[edgenum]=head[u];
    head[u]=edgenum;
}
void dfs(int u,int fa){
    maxd=max(maxd,dep[u]);
    in[u]=++dfs_clock;
    for(int i=1;i<=Log[n];i++) f[u][i]=f[f[u][i-1]][i-1];
    for(int e=head[u];e;e=Next[e]){
        int v=vet[e];
        if(v!=fa){
            f[v][0]=u;
            dep[v]=dep[u]+1;
            dfs(v,u);
        }
    }
    out[u]=dfs_clock;
}
int lca(int u,int v){
    if(dep[u]<dep[v]) swap(u,v);
    for(int i=Log[n];i>=0;i--)
        if(dep[f[u][i]]>=dep[v]) u=f[u][i];
    if(u==v) return u;
    for(int i=Log[n];i>=0;i--)
        if(f[u][i]!=f[v][i]) u=f[u][i],v=f[v][i];
    return f[u][0];
}
void add(int p,int l,int r,int x,int y){
    if(l==r){
        tree[p]+=y;
        return;
    }
    int mid=(l+r)>>1;
    if(x<=mid){
        if(!ls[p]) ls[p]=++num;
        add(ls[p],l,mid,x,y);
    }else{
        if(!rs[p]) rs[p]=++num;
        add(rs[p],mid+1,r,x,y);
    }
    tree[p]=tree[ls[p]]+tree[rs[p]];
}
int ask(int p,int l,int r,int x,int y){
    if(l==x && r==y) return tree[p];
    int mid=(l+r)>>1;
    if(y<=mid){
        if(ls[p]) return ask(ls[p],l,mid,x,y);
        else return 0;
    }else if(x>mid){
        if(rs[p]) return ask(rs[p],mid+1,r,x,y);
        else return 0;
    }else{
        int ans=0;
        if(ls[p]) ans+=ask(ls[p],l,mid,x,mid);
        if(rs[p]) ans+=ask(rs[p],mid+1,r,mid+1,y);
        return ans;
    }
}
int main(){
    scanf("%d%d",&n,&m);
    Log[0]=-1;
    for(int i=1;i<=n;i++) Log[i]=Log[i>>1]+1;
    for(int i=1;i<n;i++){
        int u,v;
        scanf("%d%d",&u,&v);
        addedge(u,v);
        addedge(v,u);
    }
    for(int i=1;i<=n;i++) scanf("%d",&t[i]);
    dep[1]=1;
//  cout<<__LINE__<<endl;
    dfs(1,-1);
//  cout<<__LINE__<<endl;
    for(int i=1;i<=m;i++) scanf("%d%d",&U[i],&V[i]);
    for(int i=1;i<=m;i++) LCA[i]=lca(U[i],V[i]);
    for(int i=1;i<=maxd;i++) rt[i]=++num;
//  cout<<__LINE__<<endl;
    for(int i=1;i<=m;i++){
        add(rt[dep[U[i]]],1,n,in[U[i]],1);
        if(LCA[i]!=1) add(rt[dep[U[i]]],1,n,in[f[LCA[i]][0]],-1);
    }
//  cout<<__LINE__<<endl;
    for(int i=1;i<=n;i++) ans[i]+=ask(rt[dep[i]+t[i]],1,n,in[i],out[i]);
//  for(int i=1;i<n;i++) printf("%d ",ans[i]);printf("%d\n",ans[n]);
//  cout<<__LINE__<<endl;
    for(int i=1;i<=num;i++) ls[i]=rs[i]=tree[i]=0;
    num=0;
    for(int i=1;i<=maxd+n+n;i++) rt[i]=++num;
    for(int i=1;i<=m;i++){
        int D=dep[U[i]]-dep[LCA[i]]*2+n+n;
        add(rt[D],1,n,in[V[i]],1);
        add(rt[D],1,n,in[LCA[i]],-1);
    }
    for(int i=1;i<=n;i++) ans[i]+=ask(rt[t[i]-dep[i]+n+n],1,n,in[i],out[i]);
    for(int i=1;i<n;i++) printf("%d ",ans[i]);printf("%d\n",ans[n]);
//  for(int i=1;i<=n;i++) printf("%d: %d %d\n",i,in[i],out[i]);
//  for(int i=1;i<=m;i++) printf("%d %d %d\n",U[i],V[i],LCA[i]);
    return 0;
} 

用的是线段树动态开点,第13个点RE,数组开到两千万也没用,不清楚是不是爆栈了。如果爆栈了怎么改呢?


by ¶凉笙 @ 2021-06-11 19:15:25

luogu不存在爆栈现象的。


by uniqueharry @ 2021-06-15 14:45:29

@hanmo0321 这边建议把所有的数组都开成 6e5 那么大,(除了您的tree和ls可能有特殊用处最好不要改


|