zoukankan      html  css  js  c++  java
  • NOIP 2016 天天爱跑步

    NOIP 2016 天天爱跑步

    洛谷传送门

    JDOJ传送门

    Description

    img

    Input

    img

    Output

    img

    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

    img

    img


    题解:

    先口胡一下部分分。

    首先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 imes 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;
    }
    
  • 相关阅读:
    Angular基础(三) TypeScript
    Angular基础(二) 组件的使用
    Angular 2基础(一) 环境搭建
    Web API 方法的返回类型、格式器、过滤器
    WebAPI路由、参数绑定
    《ASP.NET MVC企业实战》(三)MVC开发前奏
    《ASP.NET MVC企业实战》(二) MVC开发前奏
    《ASP.NET MVC企业实战》(一) MVC开发前奏
    《Inside C#》笔记(完) 程序集
    巨杉数据库助力民生银行、广发银行前台智慧化业务
  • 原文地址:https://www.cnblogs.com/fusiwei/p/13826377.html
Copyright © 2011-2022 走看看