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

    问题 G: 天天爱跑步
    时间限制: 2 Sec 内存限制: 512 MB
    提交: 24 解决: 20
    [提交][状态][讨论版]
    题目描述
    小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

    很显然要用到LCA,但正解比LCA多很多。
    一条路该分成两段,起点x到LCA,LCA到终点y。这里就要分别考虑了。对于第一段,对于其路径上的点i,t[i]==dep[x]-dep[i]时,就是dep[x]==t[i]+dep[i]。所以对于起点,就看对于点i有多少人起步于t[i]+dep[i]就好了。 那么对于第二段,len-(dep[y]-dep[i])==t[i],就是t[i]-dep[i]==len-depy,以同样的方式统计就行了。
    这只是主体思路,离实现还差很远。因为同一深度不同路径会对答案产生影响,所以可以再来一发深搜。这样判断就变得较容易了。 可以开两个桶记录先前所述的第一段和第二段对答案的贡献,但之前的会产生影响,可以这样考虑,记录搜自己和子节点之前的值,用搜完的之后的值减去他,就是自己子树要过自己的数量了。。。而为了消除LCA对答案的影响,回溯回来时,要分别把以他为LCA的起点和终点的点在两个桶中分别减减
    在这里搜答案时,我学(zhao)习(chao)神犇ljm的做法,把每个点向他所能对应的答案练了一条边。方便在dfs时查找答案,或是在回溯时减去。。

    #include<cstring>
    #include<cstdlib>
    #include<cstdio>
    #include<iostream>
    #define N 300000
    using namespace std;
    int read()
    {
        int sum=0,f=1;char x=getchar();
        while(x<'0'||x>'9'){if(x=='-')f=-1;x=getchar();}
        while(x>='0'&&x<='9'){sum=(sum<<1)+(sum<<3)+x-'0';x=getchar();}
        return sum*f;
    }
    int n,m,adj[N],f[N],vis[N],dep[N],anc[N],ans[N];
    int tim[N],A[N],sum[N],up[N*2],down[N*2];
    int e,e1,e2,e3,e4;
    int adj1[N*2],adj2[N*2],adj3[N*2],head[N];
    struct Q{int v,next,id;}q[N*2];
    struct road{int v,next;}lu[N*2],lu1[N*2],lu2[N*2],lu3[N*2];
    void add(int u,int v){lu[++e].v=v;lu[e].next=adj[u];adj[u]=e;}
    void add1(int u,int v){lu1[++e1].v=v;lu1[e1].next=adj1[u];adj1[u]=e1;}
    void add2(int u,int v){lu2[++e2].v=v;lu2[e2].next=adj2[u];adj2[u]=e2;}
    void add3(int u,int v){lu3[++e3].v=v;lu3[e3].next=adj3[u];adj3[u]=e3;}
    void add_q(int u,int v,int id){q[e4].v=v;q[e4].id=id;q[e4].next=head[u];head[u]=e4++;}
    int find(int x){return f[x]==x? x:f[x]=find(f[x]);}
    void hb(int x,int y){int fx=find(x),fy=find(y);if(fx!=fy)f[fx]=fy;}
    void dfs1(int x,int fa)
    {
        dep[x]=dep[fa]+1;anc[x]=x;vis[x]=1;
        for(int i=adj[x];i;i=lu[i].next)
        {
            int to=lu[i].v;
            if(vis[to])continue;
            dfs1(to,x);
            hb(x,to);anc[find(x)]=x;
        }
        for(int i=head[x];i!=-1;i=q[i].next)
        {
            int to=q[i].v;
            if(vis[to])ans[q[i].id]=anc[find(to)];
        }
    }
    void dfs2(int x,int y)
    {
        int t1=up[dep[x]+tim[x]],t2=down[dep[x]-tim[x]+N];
        up[dep[x]]+=A[x];
        for(int i=adj1[x];i;i=lu1[i].next)
           ++down[lu1[i].v+N];
        for(int i=adj[x];i;i=lu[i].next)
           if(lu[i].v!=y)dfs2(lu[i].v,x);
        sum[x]=up[dep[x]+tim[x]]+down[dep[x]-tim[x]+N]-t1-t2;
        for(int i=adj2[x];i;i=lu2[i].next)
        {
            int to=lu2[i].v;
            up[to]--;
            if(to==dep[x]+tim[x])
                sum[x]--;
        }
        for(int i=adj3[x];i;i=lu3[i].next)
             down[lu3[i].v+N]--;
    }
    int main()
    {
    //  freopen("runninga.in","r",stdin);
    //  freopen("runninga.out","w",stdout);
        int __size__=64<<20; 
        char *__p__=(char*)malloc(__size__)+__size__;  
        __asm__("movl %0, %%esp
    "::"r"(__p__));  
        n=read();m=read();int x,y,a,b;
        memset(head,-1,sizeof(head));
        for(int i=1;i<=n;i++)f[i]=i;
        for(int i=1;i<n;i++)x=read(),y=read(),add(x,y),add(y,x);
        for(int i=1;i<=n;i++)tim[i]=read();
        for(int i=0;i<m;i++)x=read(),y=read(),add_q(x,y,i),add_q(y,x,i);
        dfs1(1,0);
        for(int i=0;i<m;i++)
        {
            x=q[i<<1].v,y=q[i<<1|1].v;
            a=dep[x]+dep[y]-dep[ans[i]]*2;b=dep[x]-a;
            ++A[y];add1(x,b);add2(ans[i],dep[y]);add3(ans[i],b);
        }
        dfs2(1,0);
        for(int i=1;i<=n;i++)printf("%d ",sum[i]);
    }
  • 相关阅读:
    团队编程
    灯塔 ——团队展示
    碎阅创造营——项目系统设计与数据库设计
    碎阅创造营——项目需求分析
    碎阅创造营——团队编程
    碎阅创造营——团队展示
    Computer-Hunters——项目系统设计与数据库设计
    Computer-Hunters——项目需求分析
    2019软工实践——第一次团队编程作业
    Computer-Hunters——团队展示
  • 原文地址:https://www.cnblogs.com/QTY2001/p/7632700.html
Copyright © 2011-2022 走看看