标签:树链剖分
有多组样例,每组样例第一行输入两个正整数n,m(2 <= n<=50000,1<=m <= 50000),接下来n-1行,每行3个正整数a b c,(1 <= a,b <= n , a != b , 1 <= c <= 1000000000).数据保证给的路使得任意两座城市互相可达。接下来输入m行,表示m个操作,操作有两种:一. 0 a b,表示更新第a条路的过路费为b,1 <= a <= n-1 ; 二. 1 a b , 表示询问a到b最少要花多少过路费。
解题:一道 裸树的树链剖分
#include<stdio.h> #include<string.h> #define LL __int64 const int N = 50005; int head[N<<1],to[N<<1],next1[N<<1],tot; int deep[N],fath[N],son[N],num[N]; int top[N],p[N],pos; void init(){ pos=tot=0; memset(head,-1,sizeof(head)); } void addEdge(const int& u, const int& v){ to[tot] = v, next1[tot] = head[u], head[u] = tot++; } void addUndirEdge(const int& u, const int& v){ addEdge(u, v), addEdge(v, u); } void dfs1(int u,int pre,int d){ fath[u]=pre; deep[u]=d; son[u]=-1; num[u]=1; for(int i=head[u]; i!=-1; i=next1[i]){ int v=to[i]; if(v==fath[u])continue; dfs1(v,u,d+1); num[u]+=num[v]; if(son[u]==-1||num[v]>num[son[u]]) son[u]=v; } } void getpos(int u,int root){ top[u]=root; p[u]=pos++; if(son[u]==-1) return ; getpos(son[u],root); for(int i=head[u]; i!=-1; i=next1[i]){ int v=to[i]; if(v==son[u]||v==fath[u]) continue; getpos(v,v); } } LL root[N*3],cost[N]; void pushUp(int k){ root[k]=root[k<<1]+root[k<<1|1]; } void build(int l, int r, int k){ if(l==r){ root[k]=cost[l]; return ; } int mid=(l+r)>>1; build(l,mid,k<<1); build(mid+1,r,k<<1|1); pushUp(k); } void update(int l, int r, int k, const int& id, LL c){ if(l==r){ root[k]=c; return ; } int mid=(l+r)>>1; if(id<=mid) update(l,mid,k<<1,id,c); else update(mid+1,r,k<<1|1,id,c); pushUp(k); } LL query(int l, int r, int k, const int& L, const int& R){ if(L<=l&&r<=R){ return root[k]; } int mid=(l+r)>>1; LL sum=0; if(L<=mid) sum+=query(l,mid,k<<1,L,R); if(mid<R) sum+=query(mid+1,r,k<<1|1,L,R); return sum; } void swp(int &u,int &v){ int tt=u; u=v; v=tt; } LL solve(int u,int v){ int fu=top[u], fv=top[v]; LL sum=0; while(fu!=fv){ if(deep[fu]<deep[fv]){ swp(fu,fv); swp(u,v); } sum+=query(1,pos,1,p[fu],p[u]); u=fath[fu]; fu=top[u]; } if(u==v)return sum; if(deep[u]>deep[v]) swp(u,v); sum+=query(1,pos,1,p[son[u]],p[v]);//一不小心p[son[u]]写成了p[u]让我WA了好几次(求边权用p[son[u]],求点权用p[u]) return sum; } struct EDG{ int u,v; LL c; }edg[N]; int main() { int n,m,op,a,b; while(scanf("%d%d",&n,&m)>0){ init(); for(int i=1; i<n; i++){ scanf("%d%d%I64d",&edg[i].u,&edg[i].v,&edg[i].c); addUndirEdge(edg[i].u, edg[i].v); } dfs1(1,1,1); getpos(1,1); for(int i=1; i<n; i++){ if(deep[edg[i].u]>deep[edg[i].v]) swp(edg[i].u, edg[i].v); cost[p[edg[i].v]]=edg[i].c; } pos=n; build(1,pos,1); while(m--){ scanf("%d%d%d",&op,&a,&b); if(op==0) update(1,pos,1,p[edg[a].v],b); else printf("%I64d\n",solve(a,b)); } } }
标签:树链剖分
原文地址:http://blog.csdn.net/u010372095/article/details/45568287