异象石——最近公共祖先
Posted judp
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了异象石——最近公共祖先相关的知识,希望对你有一定的参考价值。
题目链接:
https://www.acwing.com/problem/content/357/
题意:
给出一个树上节点的集合,动态加入或者删除节点,询问连通所有节点的最小边集的权值之和。
解法:
把集合中的节点按照时间戳排序,每相邻两个节点距离以及首尾节点距离累加,累加之和为答案的两倍。(目前不会证明)
节点排序用set维护,首先加入0和inf,以便修改。
代码:
1 #include <bits/stdc++.h> 2 using namespace std; 3 typedef long long ll; 4 const int N=100000+5; 5 const int INF=N-1; 6 7 int n,m; 8 9 int head[N],ver[2*N],edge[2*N],nex[2*N],tot=1; 10 inline void add(int x,int y,int z) 11 12 ver[++tot]=y; 13 edge[tot]=z; 14 nex[tot]=head[x]; 15 head[x]=tot; 16 17 18 int d[N],f[N][20],max_t; 19 ll dis[N]; 20 void bfs() 21 22 max_t=log(n)/log(2)+1; 23 d[1]=1; 24 dis[1]=0; 25 queue<int> q; 26 q.push(1); 27 while(!q.empty()) 28 29 int x=q.front(); 30 q.pop(); 31 for(int i=head[x];i;i=nex[i]) 32 33 int y=ver[i]; 34 if(d[y])continue; 35 d[y]=d[x]+1; 36 dis[y]=dis[x]+edge[i]; 37 f[y][0]=x; 38 for(int i=1;i<=max_t;++i) 39 f[y][i]=f[f[y][i-1]][i-1]; 40 q.push(y); 41 42 43 44 int lca(int x,int y) 45 46 if(d[x]<d[y])swap(x,y); 47 if(d[x]>d[y]) 48 for(int i=max_t;i>=0;--i) 49 if(d[f[x][i]]>=d[y]) 50 x=f[x][i]; 51 if(x==y)return x; 52 for(int i=max_t;i>=0;--i) 53 if(f[x][i]!=f[y][i]) 54 x=f[x][i],y=f[y][i]; 55 return f[x][0]; 56 57 58 int dfn[N],to_node[N],tot2=0; 59 void dfs(int x) 60 61 dfn[x]=++tot2; 62 to_node[tot2]=x; 63 for(int i=head[x];i;i=nex[i]) 64 65 int y=ver[i]; 66 if(dfn[y])continue; 67 dfs(y); 68 69 70 71 inline ll dist(int x,int y) 72 73 if(x==0||y==0) 74 return 0; 75 return dis[x]+dis[y]-2*dis[lca(x,y)]; 76 77 78 int main() 79 80 scanf("%d",&n); 81 for(int i=1;i<n;++i) 82 83 int x,y,z; 84 scanf("%d%d%d",&x,&y,&z); 85 add(x,y,z); 86 add(y,x,z); 87 88 bfs(); 89 dfs(1); 90 scanf("%d",&m); 91 char op; 92 ll ans=0; 93 set<int> s; 94 s.insert(0); 95 s.insert(INF); 96 for(int i=0;i<m;++i) 97 98 scanf(" %c",&op); 99 if(op==‘+‘) 100 101 int x; 102 scanf("%d",&x); 103 auto r=s.insert(dfn[x]); 104 auto it=r.first,it1=it,it2=it; 105 --it1;++it2; 106 ans-=dist(to_node[*it1],to_node[*it2]); 107 ans+=dist(to_node[*it1],to_node[*it]); 108 ans+=dist(to_node[*it2],to_node[*it]); 109 110 else if(op==‘-‘) 111 112 int x; 113 scanf("%d",&x); 114 auto it=s.find(dfn[x]),it1=it,it2=it; 115 --it1;++it2; 116 ans+=dist(to_node[*it1],to_node[*it2]); 117 ans-=dist(to_node[*it1],to_node[*it]); 118 ans-=dist(to_node[*it2],to_node[*it]); 119 s.erase(it); 120 121 else 122 123 auto it1=s.begin(); 124 auto it2=s.rbegin(); 125 ++it1;++it2; 126 printf("%lld\n",(ans+dist(to_node[*it1],to_node[*it2]))/2); 127 128 129 return 0; 130
以上是关于异象石——最近公共祖先的主要内容,如果未能解决你的问题,请参考以下文章