题目链接:https://vijos.org/p/1460
http://oj.fjaxyz.com:3389/problem.php?id=223
我不禁开始怀疑,这,真的是最近公共祖先的题吗,我是从一个讲解LCA的博客里找到这道题的,然后我就乖乖的用了可爱的LCA倍增,然后我就更加愉快的TLE了。
【思路】
判断u,v 的最近公共祖先是不是u,如果是,就加上这条路线。。。
判断u,v的最近公共祖先是不是u,TLE的代码是用倍增算法做的这个,但是啊,其实我们换一种说法就是判断u是不是v的祖先
那么这就简单了,想想LCA的离线做法tarjan,里面的dfn数组,储存的是i点的dfs序号,然后实质上其实是前序遍历序号
怎么判断u是v的祖先?刚刚才提到前序遍历,那我想想后序遍历,前序是根左右,后序是左右根,那么意思就是根在前序是比叶节点序号小,在后序是比叶节点序号大
于是我们储存数组begn[] ed[]储存点的前序序号和后序序号,如果begn[u]
解决了这个问题,接下来就是求距离,我们储存数组dis表示点i到根节点的距离,
所以u,v距离就是dis[u]+dis[v]-2*dis[lca(u,v)],由于这题满足条件是u为v的祖先,所以距离简化为dis[v]-dis[u]
LCA倍增算法
1 #include2 #include 77 int u,v,w; 78 scanf("%d%d%d",&u,&v,&w); 79 adde(u,v,w); 80 } 81 build(1); 82 first(); 83 for(int i=1;i<=m;i++){ 84 int u,v; 85 scanf("%d%d",&u,&v); 86 int lca=find(u,v); 87 if(lca==u){ans+=len(u,v);cnt++;} 88 } 89 printf("%d\n%lld",cnt,ans); 90 }3 #include 4 #include 5 #include 6 #include 7 #include 8 #include 9 #define maxn 10005 10 #define ll long long 11 using namespace std; 12 13 struct node{ 14 int u,v;ll w;int nxt; 15 }e[maxn]; 16 17 int head[maxn],n,m,f[maxn][20]; 18 ll dis[maxn],ans; 19 int cnt,vis[maxn],dep[maxn]; 20 21 int tot; 22 void adde(int u,int v,int w){ 23 e[tot]=(node){u,v,w,head[u]}; 24 head[u]=tot;tot++; 25 } 26 27 void build(int u){ 28 for(int i=head[u];i!=-1;i=e[i].nxt){ 29 int v=e[i].v; 30 if(!vis[v]){ 31 f[v][0]=u; 32 dis[v]=dis[u]+e[i].w; 33 dep[v]=dep[u]+1; 34 vis[v]=1; 35 build(v); 36 } 37 } 38 } 39 40 void first(){ 41 for(int j=1;j<=16;j++){ 42 for(int i=1;i<=n;i++){ 43 f[i][j]=f[f[i][j-1]][j-1]; 44 } 45 } 46 } 47 48 int up(int x,int d){ 49 for(int i=1;i<=d;i++) 50 x=f[x][0]; 51 return x; 52 } 53 54 int find(int x,int y){ 55 if(dep[x]<dep[y])swap(x,y); 56 if(dep[x]!=dep[y]){ 57 int dd=dep[x]-dep[y]; 58 x=up(x,dd); 59 } 60 if(x==y){return x;} 61 for(int j=16;j>=0;j--){ 62 if(f[x][j]!=f[y][j]){ 63 x=f[x][j];y=f[y][j]; 64 } 65 } 66 return f[x][0]; 67 } 68 69 ll len(int u,int v){ 70 return dis[v]-dis[u]; 71 } 72 73 int main(){ 74 memset(head,-1,sizeof(head)); 75 scanf("%d%d",&n,&m); 76 for(int i=1;i ){
运用前序后序的dfs算法
1 #include2 #include 45 int u,v;long long w; 46 scanf("%d%d%lld",&u,&v,&w); 47 adde(u,v,w); 48 } 49 build(1); 50 for(int i=1;i<=m;i++){ 51 int u,v; 52 scanf("%d%d",&u,&v); 53 if(begn[u]<=begn[v]&&ed[u]>=ed[v]){ 54 ans+=dis[v]-dis[u];cnt++; 55 } 56 } 57 printf("%d\n%lld",cnt,ans); 58 }3 #include 4 #include 5 #include 6 #include 7 #include 8 #include 9 #define maxn 10005 10 using namespace std; 11 12 struct node{ 13 int u,v;long long w;int nxt; 14 }e[maxn]; 15 16 int head[maxn],n,m; 17 int cnt,vis[maxn]; 18 int begn[maxn],ed[maxn]; 19 long long ans,dis[maxn]; 20 21 int tot; 22 void adde(int u,int v,long long w){ 23 e[tot]=(node){u,v,w,head[u]}; 24 head[u]=tot;tot++; 25 } 26 27 int num,hehe; 28 void build(int u){ 29 num++;begn[u]=num; 30 for(int i=head[u];i!=-1;i=e[i].nxt){ 31 int v=e[i].v; 32 if(!vis[v]){; 33 dis[v]=dis[u]+e[i].w; 34 vis[v]=1; 35 build(v); 36 } 37 } 38 hehe++;ed[u]=hehe; 39 } 40 41 int main(){ 42 memset(head,-1,sizeof(head)); 43 scanf("%d%d",&n,&m); 44 for(int i=1;i ){
然后问题就来了,这个在vijos上AC的代码在meto code上还是WA了,我已经放弃了,因为meto code不提供错误数据也不告诉我错了几组,所以我最终还是没有在meto code上成功