思想 把树拆分成 一条一条的线段 变成1条线
首先先把树建立起来
两次dfs
第一次求 重儿子 son,每一个点的深度,父亲;
void dfs1(int r,int f) dfs1(r,0) { fa[r]=f; dep[r]=dep[f]+1; vis[r]=1; int maxz=0; sz[r]=1; //// 包含自己了的 for(ri i=0;i<p[r].size();i++) { int b=p[r][i]; if(vis[b]) continue ; dfs1(b,r); sz[r]+=sz[b]; if(maxz<sz[b]) { son[r]=b; maxz=sz[b]; } } }
第二次求dfs 建立新的 重链 排序 (用于线段树)
int id[M],hao[M]; int cur,top[M],addr[M]; void dfs2(int r,int f) { vis[r]=1; id[r]=++cur; // 树节点的新id addr[cur]=r; // 新id对应的原来的树节点 后面 建立 线段树的时候要用到。 top[r]=f; if(son[r]) dfs2(son[r],f); // 重链 for(ri i=0;i<p[r].size();i++) { int b=p[r][i]; if(vis[b]) continue; dfs2(b,b); // 新开 重链 } hao[r]=cur; // 子树 的 最后的 id }
最后 就是求树的LCA般修改
小注意: 在用线段树的时候 都是新id 调用函数的时候不要忘记了
void xlca(int a,int b,int k) /// 用到lca关于线段树的内容 都是 用 新的id 不要忘记了 { while(top[a]!=top[b]) { if(dep[top[a]]>dep[top[b]]) // 记住是看top的深度 swap(a,b); xiu(id[top[b]],id[b],1,k); // 每爬一次要更改一下 b=fa[top[b]]; } if(dep[a]>dep[b]) swap(a,b); xiu(id[a],id[b],1,k); // 线段树的 用 新id }
LAC般查询
注意:函数一定要返回 ans,不要忘记了;
long long clca(int a,int b) // int 型的函数 一定要return 不然返回就是0了 一定要记住 { long long ans=0; while(top[a]!=top[b]) { if(dep[top[a]]>dep[top[b]]) swap(a,b); ans=(ans+qu(id[top[b]],id[b],1))%P; b=fa[top[b]]; } if(dep[a]>dep[b]) swap(a,b); ans=(ans+qu(id[a],id[b],1))%P; return ans; }
线段树
4倍空间 4倍空间
修改时的向上传递不要忘记了
建树的时候 时 tr【i】=val【dras【L】】时和新ID 对应那个树点,不要直接 L;
struct xdhsu{ int l,r; long long val; }tr[M]; void build(int l,int r,int i) // 建立 线段树 { tr[i].l=l;tr[i].r=r; if(l==r) { tr[i].val=val[addr[l]]; ////// 这个很重要 l是 新的id 要找到他 对应的 原来的 那个值 return ; } int mid=(l+r)>>1; build(l,mid,i<<1); build(mid+1,r,i<<1|1); tr[i].val+=tr[i<<1].val; tr[i].val%=P; tr[i].val+=tr[i<<1|1].val; tr[i].val%=P; } int lz[M]; void down(int i) // 线段树的向下更新 , 注意懒标记是来改儿子 { if(!lz[i]) return ; lz[i<<1]+=lz[i];lz[i<<1]%=P; lz[i<<1|1]+=lz[i];lz[i<<1|1]%=P; tr[i<<1].val+=(tr[i<<1].r-tr[i<<1].l+1)*lz[i]%P; tr[i<<1|1].val+=(tr[i<<1|1].r-tr[i<<1|1].l+1)*lz[i]%P; lz[i]=0; } void xiu(int l,int r,int i,int k) { if(l>tr[i].r||r<tr[i].l) return ; if(l<=tr[i].l&&r>=tr[i].r) { tr[i].val+=(tr[i].r-tr[i].l+1)*k%P; lz[i]+=k%P; //// ky ba return ; /// 返回很重要 } down(i); xiu(l,r,i<<1,k); xiu(l,r,i<<1|1,k); tr[i].val=(tr[i<<1].val+tr[i<<1|1].val)%P; // 向上更新特别重要 } long long qu(int l,int r,int i) { if(l>tr[i].r||r<tr[i].l) return 0; if(l<=tr[i].l&&r>=tr[i].r) { return tr[i].val%P; } down(i); // 下穿 return (qu(l,r,i<<1)+qu(l,r,i<<1|1))%P; }