1 条题解

  • -1
    @ 2019-06-01 11:46:07

    时间戳的一个漂亮的应用。
    对于询问<u,v>来说,如果u能够到v,即u是v的祖先节点的话,就意味着,在树的先序遍历中,u比v先到达;在树的后序遍历中,v比u先到达。因此维护两个时间戳visit和leave,分别表示先序遍历和后序遍历中到达节点的时间。
    只要满足

    visit[u]<visit[v]&&leave[u]>leave[v]

    说明就是满足条件的<u,v>
    至于求两点间的距离,因为u是v的祖先,所以只要输出

    dis[v]-dis[u]

    即可。
    dis[i]表示根节点到i节点的距离,这个可以在dfs的过程中顺便求出。

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #define maxn 10010
    using namespace std;
    struct node{
        int from,to,val;
    }edge[maxn];
    int cnt=0,dfs_clock=0;
    int head[maxn],visit[maxn],leave[maxn],dis[maxn],indegree[maxn];
    void dfs(int u,int time){
        visit[u]=++dfs_clock;
        dis[u]=time;
        for(int i=head[u];i;i=edge[i].from){
            int v=edge[i].to;
            dfs(v,time+edge[i].val);
        }
        leave[u]=++dfs_clock;
    }
    int main(){
        //freopen("拉力赛.in","r",stdin);
        ios::sync_with_stdio(false);
        memset(head,0,sizeof(head));
        memset(visit,0,sizeof(visit));
        memset(leave,0,sizeof(leave));
        memset(dis,0,sizeof(dis));
        memset(indegree,0,sizeof(indegree));
        int n,m,a,b,t;
        cin>>n>>m;
        for(int i=1;i<n;i++){
            cin>>a>>b>>t;
            indegree[b]++;
            edge[++cnt].to=b;
            edge[cnt].val=t;
            edge[cnt].from=head[a];
            head[a]=cnt;
        }
        for(int i=1;i<=n;i++){
            if(!indegree[i]){
                dfs(i,0);
            }
        }
        int u,v;
        long long ans=0;
        long long time=0;
        for(int i=1;i<=m;i++){
            cin>>u>>v;
            if(visit[u]<visit[v]&&leave[u]>leave[v]){
                ans++;
                time+=dis[v]-dis[u];
            }
        }
        cout<<ans<<endl<<time;
        return 0;
    }
    
    
  • 1

信息

ID
1071
难度
6
分类
树结构 点击显示
标签
递交数
68
已通过
16
通过率
24%
上传者