前言
树链剖分是一个很好用的处理树上统计信息的方法,大致思想就是把树上路径分成\(log N\)条链,再用线段树之类的数据结构维护一下,所以时间复杂度得到了保障
怎么做
个人认为这篇讲的很好:
注意几点
debug树链剖分对于我来说真是个痛苦的过程,查了近一个小时错才查出来.
首先你要只要线段树上序列是什么?他们是\(dfs\_2\)中的每个树节点的\(dfs\)顺序存在\(dfn[]\)中,\(rnk[]\)则记录对应\(dfn[]\)对应的节点编号
build函数
void build(int now,int l,int r){ if(l==r){ mx[now]=sum[now]=w[rnk[l]];//注意是rnk[l] return ; } int mid=(l+r)>>1; build(now<<1,l,mid); build(now<<1|1,mid+1,r); sum[now]=sum[now<<1]+sum[now<<1|1]; mx[now]=max(mx[now<<1],mx[now<<1|1]); return ; }
dfs之前的操作
dep[1]=1,fa[1]=1;//假设root是1 dfs_1(1); dfs_2(1,1); build(1,1,n);
未完待续
例题1;
https://www.luogu.org/problemnew/show/P2590
代码:
扫描二维码关注公众号,回复: 1874801 查看本文章#include <iostream> #include <cstdio> #include <cstdlib> #include <algorithm> #include <cstring> #include <cctype> #include <map> #define ri register int #define ll long long using namespace std; const int maxn=30305; const int inf=0x7fffffff; template <class T>inline void read(T &x){ x=0;int ne=0;char c; while(!isdigit(c=getchar()))ne=c=='-'; x=c-48; while(isdigit(c=getchar()))x=(x<<3)+(x<<1)+c-48; x=ne?-x:x; return ; } int n,q,t,w[maxn],dta; int dep[maxn],size[maxn],top[maxn],son[maxn],dfn[maxn],rnk[maxn],fa[maxn],cnt=0; struct Edge{ int ne,to; }edge[maxn<<1]; int h[maxn],num_edge=0; inline void add_edge(int f,int to){ edge[++num_edge].ne=h[f]; edge[num_edge].to=to; h[f]=num_edge; } int sum[maxn<<2],mx[maxn<<2],L,R; /*inline void pushdown(int now,int ln,int rn){ if(tag[now]){ sum[now<<1]+=tag[now]*ln; sum[now<<1|1]+=tag[now]*rn; tag[now<<1]+=tag[now]; tag[now<<1|1]+=tag[now]; tag[now]=0; } return ; }*/ void build(int now,int l,int r){ if(l==r){ mx[now]=sum[now]=w[rnk[l]]; return ; } int mid=(l+r)>>1; build(now<<1,l,mid); build(now<<1|1,mid+1,r); sum[now]=sum[now<<1]+sum[now<<1|1]; mx[now]=max(mx[now<<1],mx[now<<1|1]); return ; } void update(int now,int l,int r){ if(l==r){ sum[now]=mx[now]=dta; return ; } int mid=(l+r)>>1; if(t<=mid)update(now<<1,l,mid); else update(now<<1|1,mid+1,r); sum[now]=sum[now<<1]+sum[now<<1|1]; mx[now]=max(mx[now<<1],mx[now<<1|1]); return ; } int query_mx(int now,int l,int r){ if(L<=l&&r<=R){ return mx[now]; } int mid=(l+r)>>1,ans=-inf; if(L<=mid)ans=max(ans,query_mx(now<<1,l,mid)); if(mid<R)ans=max(ans,query_mx(now<<1|1,mid+1,r)); return ans; } int query_sum(int now,int l,int r){ if(L<=l&&r<=R){ return sum[now]; } int mid=(l+r)>>1,ans=0; if(L<=mid)ans+=query_sum(now<<1,l,mid); if(mid<R)ans+=query_sum(now<<1|1,mid+1,r); return ans; } void dfs_1(int now){ int v;size[now]=1; //cout<<now<<"-----"<<endl; for(ri i=h[now];i;i=edge[i].ne){ v=edge[i].to; if(v==fa[now])continue; fa[v]=now,dep[v]=dep[now]+1; dfs_1(v); size[now]+=size[v]; if(!son[now]||size[son[now]]<size[v])son[now]=v; } return ; } void dfs_2(int now,int t){ int v;top[now]=t; dfn[now]=++cnt,rnk[cnt]=now; //cout<<now<<' '<<dfn[now]<<' '<<cnt<<endl; if(!son[now])return ; dfs_2(son[now],t); for(ri i=h[now];i;i=edge[i].ne){ v=edge[i].to; if(v==fa[now]||v==son[now])continue; dfs_2(v,v); } return ; } void query_path_sum(int x,int y){ int ans=0; while(top[x]!=top[y]){ if(dep[top[x]]<dep[top[y]])swap(x,y); L=dfn[top[x]],R=dfn[x]; ans+=query_sum(1,1,n); x=fa[top[x]]; } if(dfn[x]>dfn[y])swap(x,y); L=dfn[x],R=dfn[y]; ans+=query_sum(1,1,n); printf("%d\n",ans); return ; } void query_path_mx(int x,int y){ int ans=-inf; //cout<<x<<' '<<y<<endl; while(top[x]!=top[y]){ if(dep[top[x]]<dep[top[y]])swap(x,y); L=dfn[top[x]],R=dfn[x]; ans=max(ans,query_mx(1,1,n)); x=fa[top[x]]; } //cout<<x<<' '<<y<<endl; if(dfn[x]>dfn[y])swap(x,y); L=dfn[x],R=dfn[y]; //cout<<'-'<<L<<' '<<R<<endl; ans=max(ans,query_mx(1,1,n)); //cout<<x<<' '<<y<<endl; printf("%d\n",ans); return ; } void update_set(int x){ t=dfn[x]; update(1,1,n); return ; } int main(){ int x,y; char opt[64]; read(n); for(ri i=1;i<n;i++){ read(x),read(y); //cout<<x<<' '<<y<<endl; add_edge(x,y); add_edge(y,x); } for(ri i=1;i<=n;i++){ read(w[i]); dep[i]=fa[i]=son[i]=0; } dep[1]=1,fa[1]=1; dfs_1(1); dfs_2(1,1); build(1,1,n); read(q); while(q--){ scanf("%s",opt); if(opt[0]=='C'){ read(x),read(y); dta=y; update_set(x); } else if(opt[1]=='M'){ read(x),read(y); //cout<<x<<' '<<y<<'*'<<endl; query_path_mx(x,y); } else { read(x),read(y); query_path_sum(x,y); } } return 0; }
例题2:(待填坑)
https://www.luogu.org/problemnew/show/P3384
我比较傻逼现在还不知道为什么只得了30分
学习笔记--树链剖分
猜你喜欢
转载自www.cnblogs.com/Rye-Catcher/p/9265860.html
今日推荐
周排行