做题记录:P1600 [NOIP 2016 提高组] 天天爱跑步

这题可以发现我们的人是从 \(x\)\(lca(x,y)\) 再到 \(y\) 的,所以可以分两段考虑。

然后每一段都可以用线段树合并计算。

做完了。

#include<bits/stdc++.h>
using namespace std;
// #define int long long
#define N 300010
int n,m,tr[N],f[N][20],tot,a[N],dep[N],ans[N];
vector<int>to[N];
vector<pair<int,int>>chg[N];
struct stu{
    int ls,rs,sum;
}t[N<<5];
struct node{
    int x,y,lca;
}q[N];
void pushup(int p){
    t[p].sum=0;
    if(t[p].ls){
        t[p].sum+=t[t[p].ls].sum;
    }
    if(t[p].rs){
        t[p].sum+=t[t[p].rs].sum;
    }
}
int merge(int rta,int rtb,int l,int r){
    if(!rta){
        return rtb;
    }
    if(!rtb){
        return rta;
    }
    if(l==r){
        t[rta].sum+=t[rtb].sum;
        return rta;
    }
    int mid=(l+r)>>1;
    t[rta].ls=merge(t[rta].ls,t[rtb].ls,l,mid);
    t[rta].rs=merge(t[rta].rs,t[rtb].rs,mid+1,r);
    pushup(rta);
    return rta;
}
int add(int p,int x,int l,int r,int k){
    if(!p){
        p=++tot;
    }
    if(l==r){
        t[p].sum+=k;
        return p;
    }
    int mid=(l+r)>>1;
    if(x<=mid){
        t[p].ls=add(t[p].ls,x,l,mid,k);
    }
    else{
        t[p].rs=add(t[p].rs,x,mid+1,r,k);
    }
    pushup(p);
    return p;
}
int ask(int p,int x,int l,int r){
    if(!p){
        return 0;
    }
    if(l==r){
        return t[p].sum;
    }
    int mid=(l+r)>>1;
    if(x<=mid){
        if(t[p].ls){
            return ask(t[p].ls,x,l,mid);
        }
        return 0;
    }
    else{
        if(t[p].rs){
            return ask(t[p].rs,x,mid+1,r);
        }
        return 0;
    }
}
void init(int x,int fa){
    f[x][0]=fa;
    for(int i=1;i<=19;i++){
        f[x][i]=f[f[x][i-1]][i-1];
    }
    dep[x]=dep[fa]+1;
    for(auto y:to[x]){
        if(y==fa){
            continue;
        }
        init(y,x);
    }
}
int lca(int x,int y){
    if(x==y){
        return x;
    }
    if(dep[x]<dep[y]){
        swap(x,y);
    }
    for(int i=19;i>=0;i--){
        if(dep[f[x][i]]>=dep[y]){
            x=f[x][i];
        }
    }
    if(x==y){
        return x;
    }
    for(int i=19;i>=0;i--){
        if(f[x][i]!=f[y][i]){
            x=f[x][i];
            y=f[y][i];
        }
    }
    return f[x][0];
}
void dfs(int x,int fa){
    for(auto y:to[x]){
        if(y==fa){
            continue;
        }
        dfs(y,x);
        tr[x]=merge(tr[x],tr[y],1,3*n);
    }
    for(auto [op,pos]:chg[x]){
        tr[x]=add(tr[x],pos,1,3*n,op);
    }
    ans[x]+=ask(tr[x],dep[x]+a[x],1,3*n);
}
void dfs2(int x,int fa){
    for(auto y:to[x]){
        if(y==fa){
            continue;
        }
        dfs2(y,x);
        tr[x]=merge(tr[x],tr[y],1,3*n);
    }
    for(auto [op,pos]:chg[x]){
        tr[x]=add(tr[x],pos,1,3*n,op);
    }
    ans[x]+=ask(tr[x],a[x]-dep[x]+2*n,1,3*n);
}
signed main(){
    cin>>n>>m;
    for(int i=1;i<n;i++){
        int u,v;
        cin>>u>>v;
        to[u].push_back(v);
        to[v].push_back(u);
    }
    init(1,0);
    for(int i=1;i<=n;i++){
        cin>>a[i];
    }
    for(int i=1;i<=m;i++){
        cin>>q[i].x>>q[i].y;
        q[i].lca=lca(q[i].x,q[i].y);
        chg[q[i].x].push_back(make_pair(1,dep[q[i].x]));
        chg[f[q[i].lca][0]].push_back(make_pair(-1,dep[q[i].x]));
    }
    dfs(1,0);
    for(int i=1;i<=tot;i++){
        t[i].ls=t[i].rs=t[i].sum=0;
    }
    tot=0;
    for(int i=1;i<=n;i++){
        tr[i]=0;
        chg[i].clear();
    }
    for(int i=1;i<=m;i++){
        chg[q[i].y].push_back(make_pair(1,dep[q[i].x]-2*dep[q[i].lca]+2*n));
        chg[q[i].lca].push_back(make_pair(-1,dep[q[i].x]-2*dep[q[i].lca]+2*n));
    }
    dfs2(1,0);
    for(int i=1;i<=n;i++){
        cout<<ans[i]<<' ';
    }
    cout<<'\n';
    return 0;
}
posted @ 2025-05-11 21:12  CJZJC  阅读(11)  评论(0)    收藏  举报