【题意】给一个数,边之间有权值,然后两种操作,第一种:求任意两点的权值和,第二,修改树上两点的权值
思路:
这个题我 用的是 LCA + BIT
题目的要求是求两点之间的最短距离,然后还可以修改 边 的长度,
修改的话,我们可以用树状数组来维护,,
我们先找 dfs 序,一个点的时间戳有两个, 然后时间戳包含的就是自己的下面节点。
我们在维护树状数组的时候,在 in 时间戳 加value, 在 out 时间戳, 减 value。
这样并不会影响到兄弟节点。
既然我们可以在树状数组中修改,那我们就可以一开始就把所有数据都放在树状数组里。
树状数组维护的就是该节点到根节点的距离。-·+
这个题目是要修改边, 所以我们找 dfs 序的时候,以边的序号为节点,看看这个边包含了几个边。
一条边有两个节点,所以我们选择边的下面节点来代表这个边。选择上面的点没有意义。
最后我们是要找两点之间的距离的。
#include <iostream>
#include <cstdio>
#include <cstring>
#include <cmath>
#include <algorithm>
#define mem(x,v) memset(x,v,sizeof(x))
#define rep(i,a,b) for (int i = a; i < b; i++)
#define per(i,a,b) for (int i = a; i > b; i--)
#define low(x) ((x) & (-x))
using namespace std;
const int N = 2e5+1000;
struct edge
{
int v,id,next;
}g[N*2];
int n,q,s;
int c[N*2];
int f[N][20],dep[N],in[N],out[N],val[N];
int cnt,sign,tim;
int head[N],idn[N];
void Add_edge(int u, int v, int id){
sign++;
g[sign].next = head[u];
head[u] =sign;
g[sign].v = v;
g[sign].id = id;
return;
}
void ADD(int x, int y){
while(x <= tim){
c[x] += y;
x += (x & (-x));
}
return;
}
int sum(int x){
int ans = 0;
while(x > 0){
ans += c[x];
x -= (x & (-x));
}
return ans;
}
int lca(int x, int y){
if (dep[x] < dep[y]) swap(x,y);
for (int i = 19; i >= 0; i--)
if (dep[f[x][i]] >= dep[y]) x = f[x][i];
if (x == y)return x;
for (int i = 19; i >= 0; i--)
if (f[x][i] != f[y][i]){
x = f[x][i]; y = f[y][i]; //注意这个地方是父亲节点的比较,不是深度。
}
return f[x][0];
}
void dfs(int u, int fa, int deep){
f[u][0] = fa;
dep[u] = deep;
rep(i,1,20)
f[u][i] = f[f[u][i-1]][i-1];
for (int i = head[u]; i != -1; i = g[i].next){
edge &e = g[i];
if (e.v == fa) continue;
in[e.id] = idn[e.v] = ++tim;
dfs(e.v, u, deep+1);
out[e.id] = ++tim;
}
return;
}
int main(){
scanf("%d%d%d",&n,&q,&s);
mem(head,-1); sign = -1;
rep(i,1,n){
int x,y,z;
scanf("%d%d%d",&x,&y,&z);
Add_edge(x,y,i);
Add_edge(y,x,i);
val[i] = z;
}
tim = 0;
dfs(1,0,0);
mem(c,0);
for (int i = 1; i < n; i++){
ADD(in[i],val[i]);
ADD(out[i],-val[i]);
}
rep(i,0,q){
int x,y,z;
scanf("%d",&z);
if (z == 0) {
scanf("%d",&y);
int ans = sum(idn[s]) + sum(idn[y]) - 2*sum(idn[lca(s,y)]);
printf("%d\n",ans);
s = y;
} else{
scanf("%d%d",&x,&y);
int tot = y - val[x];
ADD(in[x],tot);
ADD(out[x],-tot);
val[x] = y;
}
}
return 0;
}