题意
一颗树,动态修改边权,询问某个点到树上最远点的距离
题解
最远点一定是树的直径的端点之一
所以问题就是动态维护树的直径
考虑用线段树维护dfs序上一段区间说代表的树的直径
合并时,直径有四种可能,分别枚举
用树状数组维护结点到根的距离
修改时,在dfs序上用树状数组修改
查询距离 (u,v)时, dis(u)+dis(v)−2∗dis(LCA(u,v))
代码
#include<bits/stdc++.h>
#define N 100010
#define INF 0x3f3f3f3f
#define eps 1e-5
#define pi 3.141592653589793
#define mod 998244353
#define P 1000000007
#define LL long long
#define pb push_back
#define fi first
#define se second
#define cl clear
#define si size
#define lb lower_bound
#define ub upper_bound
#define bug(x) cerr<<#x<<" : "<<x<<endl
#define mem(x,y) memset(x,0,sizeof(int)*(y+3))
#define sc(x) scanf("%d",&x)
#define scc(x,y) scanf("%d%d",&x,&y)
#define sccc(x,y,z) scanf("%d%d%d",&x,&y,&z)
using namespace std;
typedef pair<int,int> pp;
vector<pp> a[N];
int n,m,fa[N],f[18][N],in[N],out[N],e[N],id[N],L[N],eg[N][2],tot=0;
struct BIT{
LL d[N];
inline void up(int x,int y){for(int i=x;i<N;i+=i&-i)d[i]+=y;}
inline void update(int x,int y,int w) {up(x,w);up(y+1,-w);}
inline LL sum(int x){LL res=0;for(int i=x;i;i-=i&-i)res+=d[i];return res;}
}BT;
int son[N],top[N],sz[N];
void lable(int x,int ffa){
sz[x]=1;in[x]=++tot; id[tot]=x;
for (auto i:a[x])if (i.fi!=ffa){
L[i.fi]=L[x]+1; fa[i.fi]=x;
lable(i.fi,x);
sz[x]+=sz[i.fi];
if (sz[i.fi]>sz[son[x]]) son[x]=i.fi;
BT.update(in[i.fi],out[i.fi],e[i.se]);
}
out[x]=tot;
}
void dfs(int x,int t){
top[x]=t;
if (!son[x]) return;
dfs(son[x],t);
for(auto i:a[x]) if (i.fi!=son[x]&&i.fi!=fa[x])
dfs(i.fi,i.fi);
}
inline int lca(int x,int y){
while(top[x]!=top[y]){
if (L[top[x]]<L[top[y]]) swap(x,y);
x=fa[top[x]];
}
return L[x]<L[y]?x:y;
}
inline LL dis(int u,int v){
return BT.sum(in[u])+BT.sum(in[v])-2*BT.sum(in[lca(u,v)]);
}
struct node{
int u,v;LL d;
friend node operator + (const node a,const node b){
node c; LL tot;
c=a.d>b.d?a:b;
int x=a.u,y=a.v,u=b.u,v=b.v;
if((tot=dis(x,u))>c.d) c={x,u,tot};
if((tot=dis(x,v))>c.d) c={x,v,tot};
if((tot=dis(y,u))>c.d) c={y,u,tot};
if((tot=dis(y,v))>c.d) c={y,v,tot};
return c;
}
}g[N<<2];
void build(int x,int l,int r){
if (l==r){
g[x]={id[l],id[l],0};
return;
}
int m=l+r>>1;
build(x<<1,l,m);
build(x<<1|1,m+1,r);
g[x]=g[x<<1]+g[x<<1|1];
}
void update(int x,int l,int r,int fl,int fr){
if (l==fl&&r==fr) return;
int m=l+r>>1;
if (fr<=m) update(x<<1,l,m,fl,fr);else
if (fl>m) update(x<<1|1,m+1,r,fl,fr);else{
update(x<<1,l,m,fl,m);
update(x<<1|1,m+1,r,m+1,fr);
}
g[x]=g[x<<1]+g[x<<1|1];
}
int main(int argc, char const *argv[])
{
sc(n);
for(int i=1;i<n;i++){
int x,y;
sccc(x,y,e[i]);
eg[i][0]=x; eg[i][1]=y;
a[x].pb(pp(y,i)); a[y].pb(pp(x,i));
}
lable(1,-1);
dfs(1,1);
build(1,1,n);
sc(m);
while(m--){
char ch[3]; int x,y;
scanf("%s",ch); sc(x);
if (ch[0]=='Q'){
int u=g[1].u,v=g[1].v;
printf("%lld\n",max(dis(x,u),dis(x,v)));
}else{
sc(y);
int u=eg[x][0],v=eg[x][1];
if (fa[u]==v) swap(u,v);
BT.update(in[v],out[v],y-e[x]);
e[x]=y;
update(1,1,n,in[v],out[v]);
}
}
return 0;
}