2019 ICPC上海网络赛 A 题 Lightning Routing I (动态维护树的直径)
题目:
给定一棵树, 带边权。
现在有2种操作:
1.修改第i条边的权值。
2.询问u到其他一个任意点的最大距离是多少。
题解:
树的直径可以通过两次 dfs() 的方法求得。换句话说,到任意点最远的点,一定是直径的某个端点(反证法)。
• 因此原问题转化为动态维护直径,然后再支持询问两个点的距离,后者可以 dfs 序 + lca + 树状数组。
参考代码:
#include<bits/stdc++.h> #define lowbit(x) (x&-x) #define lson l,m,rt<<1 #define rson m+1,r,rt<<1|1 #define mkp make_pair using namespace std; typedef long long ll; typedef pair<int,int> pii; const int mod=998244353; const int INF=1<<30; const int maxn=1e5+10; struct Edge{ int u,v,w; } eg[maxn]; vector<pii> edge[maxn]; int n,q,tin[maxn],tout[maxn],rid[maxn],tot; namespace hld{ //树状数组 struct BIT{ ll a[maxn]; inline void update(int i,int x) { while(i<=n) a[i]+=x,i+=lowbit(i); } inline void update(int l,int r,int x) { update(l,x); update(r+1,-x); } inline ll query(int i) { ll res=0; while(i) res+=a[i],i-=lowbit(i); return res; } } bit; //树链剖分 int siz[maxn],dep[maxn],fa[maxn],son[maxn],top[maxn]; void dfs(int u,int f) { tin[u]=++tot; rid[tot]=u; dep[u]=dep[f]+1; fa[u]=f; siz[u]=1; son[u]=0; int m=-1; for(auto&x:edge[u]) { int v=x.first; if(v==f) continue; dfs(v,u); bit.update(tin[v],tout[v],x.second);//节点到根的距离 siz[u]+=siz[v]; if(siz[v]>m) son[u]=v,m=siz[v]; } tout[u]=tot; } void dfs(int u,int f,int tp) { top[u]=tp; if(!son[u]) return; dfs(son[u],u,tp); for(auto&x:edge[u]) { int v=x.first; if(v==f||v==son[u]) continue; dfs(v,u,v); } } void build() //树链剖分 { dfs(1,0);dfs(1,0,1); } int qlca(int u,int v) { while(top[u]!=top[v]) { if(dep[top[u]]<dep[top[v]]) swap(u,v); u=fa[top[u]]; } return dep[u]<dep[v]?u:v; } ll qdis(int u,int v) { ll r=bit.query(tin[u])+bit.query(tin[v]); int l=qlca(u,v); return r-2ll*bit.query(tin[l]); } } using hld::qdis; //线段树+树状数组动态维护树直径 struct Node{ int u,v; ll d; } tr[maxn<<2]; void pushup(int rt) { tr[rt]=tr[rt<<1].d>tr[rt<<1|1].d ? tr[rt<<1]:tr[rt<<1|1]; int x=tr[rt<<1].u,y=tr[rt<<1].v; int u=tr[rt<<1|1].u,v=tr[rt<<1|1].v; ll tot; if((tot=qdis(x,u))>tr[rt].d) tr[rt]=(Node){x,u,tot}; if((tot=qdis(x,v))>tr[rt].d) tr[rt]=(Node){x,v,tot}; if((tot=qdis(y,u))>tr[rt].d) tr[rt]=(Node){y,u,tot}; if((tot=qdis(y,v))>tr[rt].d) tr[rt]=(Node){y,v,tot}; } void build(int l,int r,int rt) { if(l==r) { int u=rid[l]; tr[rt]=(Node){u,u,0}; return ; } int m=(l+r)/2; build(lson); build(rson); pushup(rt); } void update(int L,int R,int l,int r,int rt) { if(L<=l && r<=R) return ; int m=(l+r)/2; if(L<=m) update(L,R,lson); if(R>m) update(L,R,rson); pushup(rt); } int main() { scanf("%d",&n); for(int i=1;i<n;i++) { scanf("%d%d%d",&eg[i].u,&eg[i].v,&eg[i].w); edge[eg[i].u].push_back({eg[i].v,eg[i].w}); edge[eg[i].v].push_back({eg[i].u,eg[i].w}); } hld::build(); //树链剖分 build(1,n,1); scanf("%d",&q); char op[2]; int e,v,w; for(int i=1;i<=q;++i) { scanf("%s",op); if(op[0]=='C') { scanf("%d%d",&e,&w); int u=eg[e].u,v=eg[e].v,ww=eg[e].w; if(hld::fa[v]!=u) swap(u,v); hld::bit.update(tin[v],tout[v],w-ww); eg[e].w=w; update(tin[v],tout[v],1,n,1); } else if(op[0]=='Q') { scanf("%d",&v); int x=tr[1].u,y=tr[1].v; printf("%lld\n",max(qdis(x,v),qdis(y,v))); } } return 0; }