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

     

    转载请注明出处:

    http://www.cnblogs.com/hzoi-wangxh/p/7738626.html 

    天天爱跑步

    时间限制: 2 Sec  内存限制: 512 MB

    题目描述

    小C同学认为跑步非常有趣,于是决定制作一款叫做《天天爱跑步》的游戏。《天天爱跑步》是一个养成类游戏,需要玩家每天按时上线,完成打卡任务。

       这个游戏的地图可以看作一棵包含n个结点和n-1条边的树,每条边连接两个结点,且任意两个结点存在一条路径互相可达。树上结点编号为从1到n的连续正整数。

       现在有m个玩家,第i个玩家的起点为Si,终点为Ti。每天打卡任务开始时,所有玩家在第0秒同时从自己的起点出发,以每秒跑一条边的速度,不间断地沿着最短路径向着自己的终点跑去,跑到终点后该玩家就算完成了打卡任务。(由于地图是一棵树,所以每个人的路径是唯一的)

        小C想知道游戏的活跃度, 所以在每个结点上都放置了一个观察员。 在结点的观察员会选择在第Wj秒观察玩家, 一个玩家能被这个观察员观察到当且仅当该玩家在第Wj秒也理到达了结点J  。 小C想知道每个观察员会观察到多少人?

        注意: 我们认为一个玩家到达自己的终点后该玩家就会结束游戏, 他不能等待一 段时间后再被观察员观察到。 即对于把结点J作为终点的玩家: 若他在第Wj秒重到达终点,则在结点J的观察员不能观察到该玩家;若他正好在第Wj秒到达终点,则在结点的观察员可以观察到这个玩家。

    输入

    第一行有两个整数n和m。其中n代表树的结点数量,同时也是观察员的数量,m代表玩家的数量。

    接下来n-1行每行两个整数u和v,表示结点u到结点v有一条边。

    接下来一行n个整数,其中第j个整数为Wj,表示结点j出现观察员的时间。

    接下来m行,每行两个整数Si和Ti,表示一个玩家的起点和终点。

    对于所有的数据,保证1≤Si,Ti≤n,0≤ Wj ≤n。

    输出

    输出1行n个整数,第j个整数表示结点j的观察员可以观察到多少人。

    样例输入

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

    样例输出

    2 0 0 1 1 1


    solution:
            用deep表示每个节点的深度,w表示每个观察员观察的时间。
            先用lca处理出每一个玩家起点和终点的最近公共祖先,然后用动态开点线段树去解决。
            我们可以把每一个玩家分为两步处理:向上走的和向下走的。向上走如果会被观察员观察到,deep[s]-deep[i]=w[i],再导一步deep[s]=deep[i]+w[i]。所以我们可以对于每一个玩家差分,在起点的dfs序上加1,lca的dfs序上减1,。每一层建一棵线段树,由dfs序卡出每一个节点的子树。这样,当我们全部插入后,只要查询第deep[i]+w[i]这一个深度的线段树中leftdfs[i]到rightdfs[i]区间内的权值,就可以知道从下向上走的ans[i]。
            从上向下走的比较难处理。对于向下跑的,如果玩家能被观察者i观察到,deep[s]+deep[i]-2*deep[lca[s]]=w[i].移相,得到deep[s]-2*deep[lca[s]]=w[i]-deep[i]。所以插入时在深度为deep[s]-2*deep[lca[s]]的线段树里进行差分,deep[t]处加1,deep[lca]处减1.查询时询问深度为w[i]-deep[i]线段树区间即可。
           注意,1、由于深度较大,节点多,所以使用动态开点线段树能有效节约内存。
                       2、向下走的w[i]-deep[i]可能为负数,所以应集体向右平移一个定值,数组也要相应开大一点。
                       3、做完向上跑的玩家之后,清空线段树。
    附上代码:
    #include<iostream>
    #include<cstdlib>
    #include<cstring>
    #include<cstdio>
    #include<algorithm>
    #include<cmath>
    using namespace std;
    struct tree{
        int u,v,next;
    }l[601000];
    struct tree2{
        int st,en,go;
    }ll[301000];
    int n,lian[301000],e,cnt,m,dep[301000],ldfn[301000],rdfn[301000];
    int lc[7501000],rc[7501000],w[301000],p[300100][22],root[7501000];
    int son[301000],size[301000],hh[7501000],fa[301000],an[300100],num;
    void bian(int,int);
    void dfs(int);
    void work();
    int lca(int,int);
    void change(int,int,int,int,int&);
    int search(int,int,int,int,int);
    int main()
    {
        scanf("%d%d",&n,&m);
        for(int i=1;i<n;i++)
        {
            int x,y;
            scanf("%d%d",&x,&y);
            bian(x,y);
            bian(y,x);
        }
        for(int i=1;i<=n;i++)
            scanf("%d",&w[i]);
        dfs(1);
        work();
        for(int i=1;i<=m;i++)
        {
            scanf("%d%d",&ll[i].st,&ll[i].en);
            ll[i].go=lca(ll[i].st,ll[i].en);
        }
        for(int i=1;i<=m;i++)
        {
            change(ldfn[ll[i].st],1,1,n,root[dep[ll[i].st]]);
            change(ldfn[fa[ll[i].go]],-1,1,n,root[dep[ll[i].st]]);
        }
        for(int i=1;i<=n;i++)
            an[i]+=search(ldfn[i],rdfn[i],1,n,root[dep[i]+w[i]]);
        memset(lc,0,sizeof(lc));
        memset(rc,0,sizeof(rc));
        memset(root,0,sizeof(root));
        cnt=0;
        memset(hh,0,sizeof(hh));
        for(int i=1;i<=m;i++)
        {
            change(ldfn[ll[i].en],1,1,n,root[dep[ll[i].st]-2*dep[ll[i].go]+2*n]);
            change(ldfn[ll[i].go],-1,1,n,root[dep[ll[i].st]-2*dep[ll[i].go]+2*n]);
        }
        for(int i=1;i<=n;i++)
            an[i]+=search(ldfn[i],rdfn[i],1,n,root[w[i]-dep[i]+2*n]);
        for(int i=1;i<=n;i++)
            printf("%d ",an[i]);
        return 0;
    }
    void bian(int x,int y)
    {
        e++;
        l[e].u=x;
        l[e].v=y;
        l[e].next=lian[x];
        lian[x]=e;
    }
    void dfs(int x)
    {
        ldfn[x]=++num;
        size[x]=1;
        for(int i=lian[x];i;i=l[i].next)
        {
            int v=l[i].v;
            if(v!=fa[x])
            {
                fa[v]=x;
                dep[v]=dep[x]+1;
                dfs(v);
                size[x]+=size[v];
                if(size[v]>size[son[x]])
                    son[x]=v;
            }
        }
        rdfn[x]=num;
    }
    void work()
    {
        for(int i=1;i<=n;i++)
            p[i][0]=fa[i];
        for(int i=1;i<=20;i++)
            for(int j=1;j<=n;j++)
                if(p[j][i-1]!=0)
                    p[j][i]=p[p[j][i-1]][i-1];
    }
    int lca(int x,int y)
    {
        if(dep[x]<dep[y])
            swap(x,y);
        int k=dep[x]-dep[y];
        for(int i=20;i>=0;i--)
            if(k-(1<<i)>=0)
            {
                k-=(1<<i);
                x=p[x][i];
            }
        if(x==y) return x;
        for(int i=20;i>=0;i--)
            if(p[x][i]!=0&&p[x][i]!=p[y][i])
            {
                x=p[x][i];
                y=p[y][i];
            }
        return fa[x];
    }
    void change(int x,int num,int le,int ri,int &now)
    {
        if(x==0) return;
        if(now==0)
            now=++cnt;
        hh[now]+=num;
        if(le==ri) return;
        int mid=(le+ri)>>1;
        if(x<=mid)
            change(x,num,le,mid,lc[now]);
        else
            change(x,num,mid+1,ri,rc[now]);
    }
    int search(int ll,int rr,int le,int ri,int now)
    {
        if(now==0)
            return 0;
        if(ll==le&&rr==ri)
            return hh[now];
        int mid=(le+ri)>>1;
        if(rr<=mid)
            return search(ll,rr,le,mid,lc[now]);
        else
            if(ll>mid)
                return search(ll,rr,mid+1,ri,rc[now]);
            else
                return search(ll,mid,le,mid,lc[now])+search(mid+1,rr,mid+1,ri,rc[now]);
    }
    动态开点线段树可以有很多打法,不一定像我一样打。

  • 相关阅读:
    基于element-ui图片封装组件
    计算时间间隔具体每一天
    C语言学习笔记 —— 函数作为参数
    AtCoder Beginner Contest 049 题解
    AtCoder Beginner Contest 048 题解
    AtCoder Beginner Contest 047 题解
    AtCoder Beginner Contest 046 题解
    AtCoder Beginner Contest 045 题解
    AtCoder Beginner Contest 044 题解
    AtCoder Beginner Contest 043 题解
  • 原文地址:https://www.cnblogs.com/hzoi-wangxh/p/7738626.html
Copyright © 2011-2022 走看看