https://www.cnblogs.com/violet-acmer/p/9686774.html
题意:
一对夫妇居住在xx村庄,小屋之间有双向可达的道路,不会出现环,即所构成的图是个树,从ai小屋到bi小屋需要花费wi时间,一开始,女主角在s小屋,有两个询问,
①0 u : 她又个孩子在u屋,需要妈妈接她回家,输出从s到u所需的最短时间。
②1 x val : 由于种种原因,第x条道路的行走时间由之前的w[x]变为了val。
题解:
(1)RMQ+BIT
因为树中连接两点的路径是唯一的,如果我们对顶点进行合理排列的话,能否像链状时那样,进行类似的处理呢?
考虑利用RMQ计算LCA时所用的,按DFS访问的顺序排列顶点序列。
这样,u和v之间的路径,就是在序列中u 和 v 之间的所有边减去往返重复的部分得到的结果。
于是,只要令边的权重沿叶子方向为正,沿根方向为负,那么往返重复的部分就自然抵消了,于是有
(u,v之间的花费的时间)=(从LCA(u,v)到u的花费的时间和)+(从LCA(u,v)到v的花费的时间和);
同链状情况一样,利用BIT的话,计算权重和更新边权都可以在O(logn)时间内办到,而LCA也能够在O(longn)时间内求得。
(2)树链剖分
AC代码:
![](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
1 #include<iostream> 2 #include<cstdio> 3 #include<cmath> 4 #include<cstring> 5 #include<vector> 6 using namespace std; 7 #define pb push_back 8 #define mem(a,b) (memset(a,b,sizeof a)) 9 #define lowbit(x) (x&(-x)) 10 const int maxn=1e5+50; 11 12 int n,q,s; 13 int w[maxn];//存储第 i 条边的权值 14 struct Node 15 { 16 int to; 17 int w; 18 int id; 19 Node(int to,int w,int id):to(to),w(w),id(id){} 20 }; 21 vector<Node >G[maxn]; 22 void addEdge(int u,int v,int cost,int id) 23 { 24 G[u].pb(Node(v,cost,id)); 25 G[v].pb(Node(u,cost,id)); 26 } 27 int vs[2*maxn];//欧拉序列 28 int depth[2*maxn];//深度序列 29 int id[maxn];//id[i] : 记录节点 i 在欧拉序列中第一次出现的位置 30 int es[2*maxn];//边的下标,i*2 : 叶子方向 i*2+1 : 根方向 31 int total;//记录欧拉序列的下标总个数,其实最终的 total = 2*n 32 //================BIT================== 33 int bit[2*maxn];//树状数组 34 void Add(int x,int val) 35 { 36 while(x < 2*maxn) 37 { 38 bit[x] += val; 39 x += lowbit(x); 40 } 41 } 42 int Sum(int x) 43 { 44 int sum=0; 45 while(x > 0) 46 { 47 sum += bit[x]; 48 x -= lowbit(x); 49 } 50 return sum; 51 } 52 //===================================== 53 //==================RMQ================ 54 struct RMQ 55 { 56 int dp[20][2*maxn]; 57 void Init(){ 58 for(int i=0;i < 2*maxn;++i) 59 dp[0][i]=i; 60 } 61 void ST() 62 { 63 int k=log(total)/log(2); 64 for(int i=1;i <= k;++i) 65 for(int j=0;j <= (total-(1<<i));++j) 66 if(depth[dp[i-1][j]] > depth[dp[i-1][j+(1<<(i-1))]])//dp[i][j] : 记录的是下标 67 dp[i][j]=dp[i-1][j+(1<<(i-1))]; 68 else 69 dp[i][j]=dp[i-1][j]; 70 } 71 int Lca(int u,int v) 72 { 73 if(u > v) 74 swap(u,v); 75 int k=log(v-u+1)/log(2); 76 if(depth[dp[k][u]] > depth[dp[k][v-(1<<k)+1]]) 77 return vs[dp[k][v-(1<<k)+1]]; 78 return vs[dp[k][u]];//返回 u,v 的lca 79 } 80 }_rmq; 81 //===================================== 82 void Dfs(int u,int f,int d) 83 { 84 vs[total]=u; 85 depth[total]=d; 86 id[u]=total++; 87 for(int i=0;i < G[u].size();++i) 88 { 89 Node &e=G[u][i]; 90 if(e.to != f) 91 { 92 Add(total,e.w);//叶子方向,+e.w 93 es[2*e.id]=total;//记录朝向叶子方向的边 94 Dfs(e.to,u,d+1); 95 vs[total]=u; 96 depth[total++]=d; 97 Add(total,-e.w);//根方向, -e.w 98 es[2*e.id+1]=total;//记录朝向根方向的边 99 } 100 } 101 } 102 void Init() 103 { 104 _rmq.Init(); 105 total=0; 106 mem(bit,0); 107 for(int i=0;i < maxn;++i) 108 G[i].clear(); 109 } 110 int main() 111 { 112 while(~scanf("%d%d%d",&n,&q,&s)) 113 { 114 Init(); 115 for(int i=1;i < n;++i) 116 { 117 int u,v; 118 scanf("%d%d%d",&u,&v,w+i); 119 addEdge(u,v,w[i],i); 120 } 121 Dfs(1,-1,0); 122 _rmq.ST(); 123 for(int i=1;i <= q;++i) 124 { 125 int type; 126 scanf("%d",&type); 127 if(type == 0) 128 { 129 int u; 130 scanf("%d",&u); 131 int lca=_rmq.Lca(id[u],id[s]); 132 printf("%d\n",Sum(id[u])+Sum(id[s])-2*Sum(id[lca])); 133 s=u; 134 } 135 else 136 { 137 int x,val; 138 scanf("%d%d",&x,&val); 139 Add(es[x*2],val-w[x]);//w[x] 变为 val,需要在原基础上加上 val-w[x] 140 Add(es[x*2+1],w[x]-val);//朝向根方向的加负值 141 w[x]=val; 142 } 143 } 144 } 145 return 0; 146 }