POJ 2763 /// 基於邊權的樹鏈剖分
阿新 • • 發佈:2018-11-21
n) img namespace head view date oid 線段樹 clas
題目大意:
給定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 #defineView Coderoot 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; }
POJ 2763 /// 基於邊權的樹鏈剖分