随笔- 71  文章- 0  评论- 150 

传送门

将每个玩家的路径看作两部分:向根上行以及向叶子下行

p为每个点出现观察员的时间。子树中的起点u到当前点v的路径即是上行,如果dep[v]+p[v]=dep[u],则u对v产生一个贡献。当前点u到子树中终点v的路径即是下行,如果dep[v]-dis(x,v)=dep[u]-p[u](x为这条路径的起点,v为终点,dis(x,v)为两点的距离),则v对u产生一个贡献。

树上差分,将所有路径标记到树上。开两个桶分别存所有起点的dep[x]和所有终点的dep[x]-dis,在起点和终点处使贡献+1,在lca处把它们的贡献分别-1,表示出了这棵子树以后不再产生贡献。统计答案的时候,如果一条路径对lca产生了贡献,那么起点和终点都会算一次,因此lca处将贡献-1的时候要判断是否被这条路径贡献了答案。

查询某棵子树中点的答案的时候,有可能其它子树的贡献仍然留在桶内。由于这道题只是记录贡献的累计,因此在dfs到达某个点的时候记录一次答案,将要出这个点的时候再查询一次答案,减去第一次记录的值使差值成为最终答案。

统计某个点的答案时,先把所有+1的贡献扔进桶里,进行查询,再处理所有贡献-1的操作。

#include<iostream>
#include<cstdio>
#include<vector>
using namespace std;
const int N=300010,M=300010;
int n,m,a[N];
int ver[2*N],Next[2*N],head[N],tot;
int dep[N],ans[2][N];
int c[2][600010];
struct node{
    int opt,val,x,dis;
    node(int a=0,int b=0,int c=0,int d=0){
        opt=a,val=b,x=c,dis=d;
    }
};
vector<node>s[N];
void add(int x,int y){
    ver[++tot]=y;
    Next[tot]=head[x];
    head[x]=tot;
}
int st[N][21];
void dfs(int x,int fa){
    for(int i=1;i<=20;i++){
        st[x][i]=st[st[x][i-1]][i-1];
        if(!st[x][i])break;
    }
    for(int i=head[x];i;i=Next[i]){
        int y=ver[i];
        if(y==fa)continue;
        dep[y]=dep[x]+1;
        st[y][0]=x;
        dfs(y,x); 
    }
}
int get(int x,int y){
    if(dep[x]<dep[y])swap(x,y);
    for(int i=20;i>=0;i--){
        if(st[x][i]&&dep[st[x][i]]>=dep[y])x=st[x][i];
    }
    if(x==y)return x;
    for(int i=20;i>=0;i--){
        if(st[x][i]!=st[y][i]){
            x=st[x][i],y=st[y][i];
        }
    }
    return st[x][0];
}
void dfs1(int x,int fa){
    ans[0][x]=c[0][dep[x]+a[x]];
    ans[1][x]=c[1][dep[x]-a[x]+N];
    for(int i=head[x];i;i=Next[i]){
        int y=ver[i];
        if(y==fa)continue;
        dfs1(y,x);
    }
    for(int i=0;i<s[x].size();i++){
        int v=s[x][i].x,val=s[x][i].val,opt=s[x][i].opt,dis=s[x][i].dis;
        if(val==-1)continue;
        if(opt==0){
            c[0][dep[v]]+=val;
        }
        else{
            c[1][dep[v]-dis+N]+=val;
        }
    }
    ans[0][x]=c[0][dep[x]+a[x]]-ans[0][x];
    ans[1][x]=c[1][dep[x]-a[x]+N]-ans[1][x];
    for(int i=0;i<s[x].size();i++){
        int v=s[x][i].x,val=s[x][i].val,opt=s[x][i].opt,dis=s[x][i].dis;
        if(val==1)continue;
        if(opt==0){
            c[0][dep[v]]+=val;
            if(dep[x]+a[x]==dep[v])ans[0][x]--;
        }
        else{
            c[1][dep[v]-dis+N]+=val;
        }
    }
}
int main()
{
    scanf("%d%d",&n,&m);
    for(int i=1,x,y;i<n;i++){
        scanf("%d%d",&x,&y);
        add(x,y),add(y,x);
    }
    for(int i=1;i<=n;i++)scanf("%d",&a[i]);
    dfs(1,0);
    for(int i=1,x,y;i<=m;i++){
        scanf("%d%d",&x,&y);
        int lca=get(x,y);
        int dis=dep[x]+dep[y]-2*dep[lca];
        s[x].push_back(node(0,1,x,0));
        s[y].push_back(node(1,1,y,dis));
        s[lca].push_back(node(0,-1,x,0));
        s[lca].push_back(node(1,-1,y,dis));
    }
    dfs1(1,0);
    for(int i=1;i<=n;i++){
        printf("%d ",ans[0][i]+ans[1][i]);
    }
    return 0;
}
View Code

 

 posted on 2019-11-14 19:59  Chloris_Black  阅读(...)  评论(...编辑  收藏