POJ 2763 /// 基于边权的树链剖分
题目大意:
给定n个结点,有n-1条无向边,给定每条边的边权
两种操作,第一种:求任意两点之间路径的权值和,第二种:修改树上一点的权值。
因为是一棵树,可以直接把 u点和v点间(假设u为父节点,v为子节点)的边 的边权往下给v点
这样就转换成了点权,那么此时查询 u点到v点之间路径的权值和 的话
由于u点存有 u的父节点到u 的边权,所以应该查询的是 u到v的路径上 的第二个点到v的权值和
修改查询树上两结点间路径长度的函数 int queryPath(int x,int y){ } 中求最后一步的部分 /// 点权版本 if(p[x]>p[y]) swap(x,y); return ans+query(p[x],p[y],1,pos,1); /// 边权版本 if(x==y) return ans; if(dep[x]>dep[y]) swap(x,y); return ans+query(p[son[x]],p[y],root);
#include <stdio.h> #include <cstring> #include <algorithm> using namespace std; #define mem(i,j) memset(i,j,sizeof(i)) #define lson l,m,rt<<1 #define rson m+1,r,rt<<1|1 #define root 1,n,1 const int maxn=1e5+5; int n,q,s; struct QTree { struct EDGE { int to,ne; }e[maxn<<1]; int head[maxn], tot; void add(int u,int v) { e[tot].to=v; e[tot].ne=head[u]; head[u]=tot++; } int fa[maxn], son[maxn], dep[maxn], num[maxn]; int top[maxn], p[maxn], fp[maxn], pos; int sumT[maxn<<2]; void init() { tot=1; mem(head,0); pos=0; mem(son,0); } // --------------------以下是线段树------------------------- void pushup(int rt) { sumT[rt]=sumT[rt<<1]+sumT[rt<<1|1]; } void build(int l,int r,int rt) { if(l==r) { sumT[rt]=0; return ; } int m=(l+r)>>1; build(lson), build(rson); pushup(rt); } void update(int k,int w,int l,int r,int rt) { if(l==r) { sumT[rt]=w; return; } int m=(l+r)>>1; if(k<=m) update(k,w,lson); else update(k,w,rson); pushup(rt); } int query(int L,int R,int l,int r,int rt) { if(L<=l && r<=R) return sumT[rt]; int m=(l+r)>>1, res=0; if(L<=m) res+=query(L,R,lson); if(R>m) res+=query(L,R,rson); return res; } // --------------------以上是线段树------------------------- // --------------------以下是树链剖分------------------------- void dfs1(int u,int pre,int d) { dep[u]=d; fa[u]=pre; num[u]=1; for(int i=head[u];i;i=e[i].ne) { int v=e[i].to; if(v!=fa[u]) { dfs1(v,u,d+1); num[u]+=num[v]; if(!son[u] || num[v]>num[son[u]]) son[u]=v; } } } void dfs2(int u,int sp) { top[u]=sp; p[u]=++pos; fp[p[u]]=u; if(!son[u]) return; dfs2(son[u],sp); for(int i=head[u];i;i=e[i].ne) { int v=e[i].to; if(v!=son[u] && v!=fa[u]) dfs2(v,v); } } int queryPath(int x,int y) { int ans=0; int fx=top[x], fy=top[y]; while(fx!=fy) { if(dep[fx]>=dep[fy]) { ans+=query(p[fx],p[x],root); x=fa[fx]; } else { ans+=query(p[fy],p[y],root); y=fa[fy]; } fx=top[x], fy=top[y]; } if(x==y) return ans; if(dep[x]>dep[y]) swap(x,y); return ans+query(p[son[x]],p[y],root); } // --------------------以上是树链剖分------------------------- void initQTree() { dfs1(1,0,0); dfs2(1,1); build(root); } }T; int E[maxn][3]; int main() { while(~scanf("%d%d%d",&n,&q,&s)) { T.init(); for(int i=1;i<n;i++) { int u,v,w; scanf("%d%d%d",&u,&v,&w); E[i][0]=u, E[i][1]=v, E[i][2]=w; T.add(u,v); T.add(v,u); } T.initQTree(); for(int i=1;i<n;i++) { if(T.dep[E[i][0]]>T.dep[E[i][1]]) swap(E[i][0],E[i][1]); T.update(T.p[E[i][1]],E[i][2],root); } while(q--) { int op; scanf("%d",&op); if(op) { int k,w; scanf("%d%d",&k,&w); T.update(T.p[E[k][1]],w,root); } else { int v; scanf("%d",&v); printf("%d\n",T.queryPath(s,v)); s=v; } } } return 0; }