NOIP 2016 天天爱跑步

洛谷传送门

JDOJ传送门

Description

NOIP 2016 天天爱跑步_#include

Input

NOIP 2016 天天爱跑步_i++_02

Output

NOIP 2016 天天爱跑步_差分_03

Sample Input

6 3 2 3 1 2 1 4 4 5 4 6 0 2 5 1 2 3 1 5 1 3 2 6

Sample Output

2 0 0 1 1 1

HINT

NOIP 2016 天天爱跑步_差分_04

NOIP 2016 天天爱跑步_i++_05


题解:

先口胡一下部分分。

首先1号、2号,只有0时刻出现的观察员能够看到人,所有人都在0时刻出现。那么树上差分统计人数即可。

3号、4号,也是只有0时刻观察员,只统计起点即可。

5号,暴力可过。

9-12号,由于起点固定,所以每个人跑到每个点的时间可以用性质算出来,然后按这个性质统计即可。

13-16号同理。

那么再考虑正解。

9-12和13-16号点可以给我们很大的启发:我们发现针对起点为1、终点为1的路径,都是按性质走的,所以我们就可以得到一个启发:将一条路径拆分成两个支路来解决。这样的话,这样的两条之路可以分别利用性质来处理。

这个性质是:在上行路径上,满足

\[deep[s]-deep[x]=t[x] \]

这样的点是对答案有贡献的。

在下行路径上,满足

\[deep[s]+deep[x]-2\times deep[lca]=t[x] \]

这样的点是对答案有贡献的。

那么对于每一个节点\(x\),根据以上性质,就有\(deep[s]=deep[x]+t[x]\),也就是说,对于一条起点为s的上行路径来讲,它会对这个路径上所有满足这个性质的点作贡献。

下行路径同理。

那么怎么处理呢?思路到这里,权值线段树的想法就比较自然了。按起始节点s的深度deep[s]来统计人数。所以我们可以考虑用权值线段树(动态开点)来维护这个信息。然后通过树上差分快速处理新路径。最后只需要从下到上线段树合并统计即可。

注意,上行和下行要统计两遍。

代码:

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
char *p1,*p2,buf[100000];
#define nc() (p1==p2 && (p2=(p1=buf)+fread(buf,1,100000,stdin),p1==p2)?EOF:*p1++)
int read()
{
    int x=0,f=1;
    char ch=nc();
    while(ch<'0'||ch>'9')
    {
        if(ch=='-')
            f=-1;
        ch=nc();
    }
    while(ch>='0'&&ch<='9')
        x=x*10+ch-'0',ch=nc();
   	return x*f;
}
const int maxn=3*1e5+10;
int n,m,maxx;
int tot,to[maxn<<1],nxt[maxn<<1],head[maxn];
int t[maxn];
int top[maxn],fa[maxn],deep[maxn],size[maxn],son[maxn];
int b[maxn],e[maxn],lcaa[maxn];
int sum[maxn*50],lson[maxn*50],rson[maxn*50],cnt;
int root[maxn],ans[maxn];
void add(int x,int y)
{
    to[++tot]=y;
    nxt[tot]=head[x];
    head[x]=tot;
}    
void dfs1(int x,int f)
{
    deep[x]=deep[f]+1;
    fa[x]=f;
    size[x]=1;
    for(int i=head[x];i;i=nxt[i])
    {
        int y=to[i];
        if(y==f)
            continue;
        dfs1(y,x);
        size[x]+=size[y];
        if(!son[x]||size[y]>size[son[x]])
            son[x]=y;
    }
}
void dfs2(int x,int t)
{
    top[x]=t;
    if(!son[x])
        return;
    dfs2(son[x],t);
    for(int i=head[x];i;i=nxt[i])
    {
        int y=to[i];
        if(y==fa[x]||y==son[x])
            continue;
        dfs2(y,y);
    }
}
int lca(int x,int y)
{
    while(top[x]!=top[y])
    {
        if(deep[top[x]]<deep[top[y]])
            swap(x,y);
        x=fa[top[x]];
    }
    return deep[x]<deep[y]?x:y;
}
void pushup(int pos)
{
    sum[pos]=sum[lson[pos]]+sum[rson[pos]];
}
void update(int &pos,int l,int r,int x,int k)
{
    int mid=(l+r)>>1;
    if(!pos)
        pos=++cnt;
    if(l==r)
    {
        sum[pos]+=k;
        return;
    }
    if(x<=mid)
        update(lson[pos],l,mid,x,k);
    else
        update(rson[pos],mid+1,r,x,k);
    pushup(pos);
}
int query(int pos,int l,int r,int x)
{
    int mid=(l+r)>>1;
    if(l==r)
        return sum[pos];
    if(x<=mid)
        return query(lson[pos],l,mid,x);
    else
        return query(rson[pos],mid+1,r,x);
}
void merge(int &x,int y,int l,int r)
{
    int mid=(l+r)>>1;
    if(!x||!y)
    {
        x=(!x?y:x);
        return;
    }
    if(l==r)
        sum[x]+=sum[y];
    merge(lson[x],lson[y],l,mid);
    merge(rson[x],rson[y],mid+1,r);
}
void dfs3(int x)
{
    for(int i=head[x];i;i=nxt[i])
    {
        int y=to[i];
        if(y==fa[x])
            continue;
        dfs3(y);
        merge(root[x],root[y],1,maxx);
    }
    if(n+deep[x]+t[x]<=maxx)
        ans[x]+=query(root[x],1,maxx,n+deep[x]+t[x]);
}
void dfs4(int x)
{
    for(int i=head[x];i;i=nxt[i])
    {
        int y=to[i];
        if(y==fa[x])
            continue;
        dfs4(y);
        merge(root[x],root[y],1,maxx);
    }
    ans[x]+=query(root[x],1,maxx,n+deep[x]-t[x]);
}
int main()
{
    n=read();m=read();
    for(int i=1;i<n;i++)
    {
        int x,y;
        x=read();y=read();
        add(x,y);
        add(y,x);
    }
    for(int i=1;i<=n;i++)
        t[i]=read();
    dfs1(1,0);
    dfs2(1,1);
    maxx=n<<1;
    for(int i=1;i<=m;i++)
    {
        b[i]=read(),e[i]=read();
        lcaa[i]=lca(b[i],e[i]);
        update(root[b[i]],1,maxx,deep[b[i]]+n,1);
        update(root[fa[lcaa[i]]],1,maxx,deep[b[i]]+n,-1);
    }
    dfs3(1);
    cnt=0;
    memset(root,0,sizeof(root));
    memset(sum,0,sizeof(sum));
    memset(lson,0,sizeof(lson));
    memset(rson,0,sizeof(rson));
    for(int i=1;i<=m;i++)
    {
        update(root[e[i]],1,maxx,n-deep[b[i]]+2*deep[lcaa[i]],1);
        update(root[lcaa[i]],1,maxx,n-deep[b[i]]+2*deep[lcaa[i]],-1);
    }
    dfs4(1);
    for(int i=1;i<n;i++)
        printf("%d ",ans[i]);
    printf("%d",ans[n]);
    return 0;
}