天天爱跑步

题目链接:Click here

Solution:

首先orz@WYBIACX,蒟蒻本来不怎么会,看了大佬题解才会

写完这题后有所收获,所以特此总结一下

对于每条路径,我们可以把它拆成\(u\rightarrow lca(u,v)\)\(lca(u,v)\rightarrow v\)来考虑

对于\(u\rightarrow lca\)这条路径上的点\(x\),显然仅当\(dep[x]+w[x]=dep[u]\)时,\(u\)才会对\(x\)造成造成贡献

则第一次计算,我们对一个点,定义它的权值为\(dep[x]\),用一个桶去维护数量

对于\(lca\rightarrow v\)这条路经上的点,首先就可以得出当\(dis(u,x)=w[x]\)时,\(u\)\(x\)可以造成贡献

但是我们如果直接这样算,是无法利用桶去维护的,则考虑如何转化

\(dis(u,x)-dep[x]=w[x]-dep[x]\)\(dis(u,v)-dep[v]=w[x]-dep[x]\)

则对于\(lca\rightarrow v\)这条路径上的点,当\(dis(u,v)-dep[v]=w[x]-dep[x]\)时有贡献,我们同样用一个桶来维护

要注意的是一条路径是不能对他们\(lca\)以上的点造成影响的,所以要在他们的\(lca\)处在桶内减掉他们

还有,当\(lca\)可以观测到这条路径上的点时,它会被算两次,我们应该减去多算的

最后,桶的下标并不一定是正数,所以我们要把下标值加上\(maxn\)

Code:

#include<bits/stdc++.h>
const int N=3e5+11;
using namespace std;
int n,m,cnt,head[N],w[N],fa[N];
int son[N],sz[N],dep[N],ans[N];
int num[N],top[N],bucket[N*3];
vector<int> v1[N],v2[N],v3[N];
struct Edge{int nxt,to;}edge[N<<1];
int read(){
    int x=0,f=1;char ch=getchar();
    while(!isdigit(ch)){if(ch=='-')f=-f;ch=getchar();}
    while(isdigit(ch)){x=x*10+ch-48;ch=getchar();}
    return x*f;
}
void ins(int x,int y){
    edge[++cnt].nxt=head[x];
    edge[cnt].to=y;head[x]=cnt;
}
void dfs1(int x,int fat){
    for(int i=head[x];i;i=edge[i].nxt){
        int y=edge[i].to;
        if(y==fat) continue;
        fa[y]=x;dep[y]=dep[x]+1;
        dfs1(y,x);sz[x]+=sz[y];
        if(sz[y]>sz[son[x]]) son[x]=y;
    }++sz[x];
}
void dfs2(int x,int topx){
    top[x]=topx;
    if(!son[x]) return ;
    dfs2(son[x],topx);
    for(int i=head[x];i;i=edge[i].nxt){
        int y=edge[i].to;
        if(y==fa[x]||y==son[x]) continue;
        dfs2(y,y);
    }
}
int Lca(int x,int y){
    while(top[x]!=top[y]){
        if(dep[top[x]]<dep[top[y]]) swap(x,y);
        x=fa[top[x]];
    }return dep[x]<dep[y]?x:y;
}
int dis(int x,int y){
    return dep[x]+dep[y]-(dep[Lca(x,y)]<<1);
}
void calc1(int x){
    int pre=bucket[dep[x]+w[x]+N];
    for(int i=head[x];i;i=edge[i].nxt){
        int y=edge[i].to;
        if(y==fa[x]) continue;
        calc1(y);
    }
    bucket[dep[x]+N]+=num[x];
    ans[x]+=bucket[dep[x]+w[x]+N]-pre;
    for(int i=0;i<v1[x].size();i++)
        --bucket[dep[v1[x][i]]+N];
}
void calc2(int x){
    int pre=bucket[w[x]-dep[x]+N];
    for(int i=head[x];i;i=edge[i].nxt){
        int y=edge[i].to;
        if(y==fa[x]) continue;
        calc2(y);
    }
    for(int i=0;i<v3[x].size();i++)
        ++bucket[dis(x,v3[x][i])-dep[x]+N];
    ans[x]+=bucket[w[x]-dep[x]+N]-pre;
    for(int i=0;i<v2[x].size();i++)
        --bucket[v2[x][i]+N];
}
signed main(){
    n=read(),m=read();
    for(int i=1;i<n;i++){
        int x=read(),y=read();
        ins(x,y),ins(y,x);
    }
    for(int i=1;i<=n;i++) w[i]=read();
    dfs1(1,0);dfs2(1,1);
    for(int i=1;i<=m;i++){
        int x=read(),y=read();
        num[x]++;int lca=Lca(x,y);
        v1[lca].push_back(x);
        v2[lca].push_back(dis(x,y)-dep[y]);
        v3[y].push_back(x);
        if(dep[lca]+w[lca]==dep[x]) --ans[lca];
    }
    calc1(1);calc2(1);
    for(int i=1;i<=n;i++)
        printf("%d ",ans[i]);
    return 0;
}
posted @ 2019-09-16 16:20  DQY_dqy  阅读(190)  评论(2编辑  收藏  举报