1 条题解
-
-1yejun LV 10 MOD @ 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