树链剖分模板
代码
//input(输入是先输N,再输N-1条边带权),调用dfs和Div,然后建线段树,更新每个点的值 //Find用于找两个点之间的最大值或其他,Update用于单点更新,如果成段更新于Find写得类似 #define tu nod[u] #define tv nod[v] #define e tree[id] #define lson tree[id*2] #define rson tree[id*2+1] int N; struct node{ int top,fa,deep,s,p,fp,son; }; struct edge { int u,v,c; edge(int u=0,int v=0,int c=0):u(u),v(v),c(c){} }E[maxn]; struct Tree{ int le,ri,v; }; struct DivTree { int pid; vector<int> G[maxn]; node nod[maxn]; Tree tree[4*maxn]; void init() { pid=0; for(int i=0;i<maxn;i++) G[i].clear(),nod[i].son=-1; //初始化 } void dfs(int u,int fa,int deep) { tu.fa=fa,tu.deep=deep,tu.s=1; //保存父节点,深度,大小为1 int Size=G[u].size(); for(int i=0;i<Size;i++) { int v=G[u][i]; if(v==fa) continue; //父亲不管 dfs(v,u,deep+1); tu.s+=tv.s; //加上大小 if(tu.son==-1||tv.s>nod[tu.son].s) tu.son=v; //找重链所指向的点 } } void Div(int u,int top) { tu.top=top; //重链顶点 tu.p=++pid; //重新编号 nod[tu.p].fp=u; if(tu.son!=-1) Div(tu.son,top); //有重链继续往下找 else return; int Size=G[u].size(); for(int i=0;i<Size;i++) { int v=G[u][i]; if(v==tu.fa||v==tu.son) continue; Div(v,v); //新的重链 } } void pushup(int id){ e.v=max(lson.v,rson.v); } void Build_tree(int id,int le,int ri) { e.le=le,e.ri=ri,e.v=0; if(le==ri) return; int mid=(le+ri)/2; Build_tree(id*2,le,mid); Build_tree(id*2+1,mid+1,ri); } void Update(int id,int k,int v) { int le=e.le,ri=e.ri; if(le==ri){ e.v=v; return; } int mid=(le+ri)/2; if(k<=mid) Update(id*2,k,v); else Update(id*2+1,k,v); pushup(id); } int Query(int id,int x,int y) { int le=e.le,ri=e.ri; if(x<=le&&ri<=y) return e.v; int mid=(le+ri)/2; int ret=0; if(x<=mid) ret=max(ret,Query(id*2,x,y)); if(y>mid) ret=max(ret,Query(id*2+1,x,y)); return ret; } int Find(int u,int v) { int f1=tu.top,f2=tv.top; int ret=0; while(f1!=f2) //不在同一条链上 { if(nod[f1].deep<nod[f2].deep) //总是让u是深度大的点 { swap(f1,f2); swap(u,v); } ret=max(ret,Query(1,nod[f1].p,tu.p)); //查询这条链 u=nod[f1].fa; f1=tu.top; //跳到父节点去 } if(u==v) return ret; //相同 if(tu.deep>tv.deep) swap(u,v); ret=max(ret,Query(1,nod[tu.son].p,tv.p)); //查询同一条链上的这段区间 return ret; } void input() //输入是输入一个N,再输入N-1条带权边 { scanf("%d",&N); init(); for(int i=1;i<N;i++) { int u,v,c; scanf("%d%d%d",&u,&v,&c); E[i]=edge(u,v,c); //边 G[u].push_back(v); G[v].push_back(u); } dfs(1,0,0); Div(1,1); Build_tree(1,1,pid); //建树 for(int i=1;i<N;i++) { edge& t=E[i]; int& u=t.u; int& v=t.v; if(tu.deep>tv.deep) swap(u,v); Update(1,tv.p,t.c); //修改边权,偏向v } } };