From: 雷蒻 <34390285+hsfzLZH1@users.noreply.github.com> Date: Thu, 2 May 2019 07:50:32 +0000 (+0800) Subject: Update dynamic-tree-divide.md X-Git-Url: http://git.osdn.net/view?a=commitdiff_plain;h=ffbe2784b383dbee5095348a400c780de20d46a2;p=oi-wiki%2Fmain.git Update dynamic-tree-divide.md 完善了例题 luogu P2056 --- diff --git a/docs/graph/dynamic-tree-divide.md b/docs/graph/dynamic-tree-divide.md index fbc2d072..09e8d01c 100644 --- a/docs/graph/dynamic-tree-divide.md +++ b/docs/graph/dynamic-tree-divide.md @@ -50,7 +50,7 @@ int main() 在查询和修改的时候,我们在点分树上暴力跳父亲修改。由于点分树的深度最多是 $O(\log_2 n)$ 的,所以这样做复杂度能得到保证。 -在动态点分治的过程中,需要一个结点到其点分树上的祖先的距离等其他信息,由于一个点最多有 $O(\log_2 n)$ 个祖先,我们可以在计算点分树时额外计算深度 ```dep[x]``` 或使用 LCA ,预处理出这些距离或实现实时查询。 +在动态点分治的过程中,需要一个结点到其点分树上的祖先的距离等其他信息,由于一个点最多有 $O(\log_2 n)$ 个祖先,我们可以在计算点分树时额外计算深度 $dep[x]$ 或使用 LCA ,预处理出这些距离或实现实时查询。 在动态点分治的过程中,一个结点在其点分树上的祖先结点的信息中可能会被重复计算,这是我们需要消去重复部分的影响。一般的方法是对于一个联通块用两种方式记录:一个是其到分治中心的距离信息,另一个是其到点分树上分治中心父亲的距离信息。这一部分内容将在例题中得到展现。 @@ -62,6 +62,178 @@ int main() 2. 询问树上两个最远的黑点的距离。 - $n\le 10^5,m\le 5\times 10^5$ - +$n\le 10^5,m\le 5\times 10^5$ +求出点分树,对于每个结点 $x$ 维护两个 ** 可删堆 ** 。 $dist[x]$ 存储结点 $x$ 代表的联通块中的所有黑点到 $x$ 的距离信息, $ch[x]$ 表示结点 $x$ 在点分树上的所有儿子和它自己中的黑点到 $x$ 的距离信息,由于本题贪心的求答案方法,且两个来自于同一子树的路径不能成为一条完成的路径,我们只在这个堆中插入其自己的值和其每个子树中的最大值。我们发现, $ch[x]$ 中最大的两个值(如果没有两个就是所有值)的和就是分治时分支中心为 $x$ 时经过结点 $x$ 的最长黑端点路径。我们可以用可删堆 $ans$ 存储所有结点的答案,这个堆中的最大值就是我们所求的答案。 + +我们可以根据上面的定义维护 $dist[x],ch[x],ans$ 这些可删堆。当 $dist[x]$ 中的值发生变化时,我们也可以在 $O(\log_2 n)$ 的时间复杂度内维护 $ch[x],ans$ 。 + +现在我们来看一下,当我们反转一个点的颜色时, $dist[x]$ 值会发生怎样的改变。当结点原来是黑色时,我们要进行的是删除操作;当结点原来是白色时,我们要进行的是插入操作。 + +假如我们要反转结点 $x$ 的颜色。对于其所有祖先 $u$ ,我们在 $dist[u]$ 中插入或删除 $dist(x,u)$ ,并同时维护 $ch[x],ans$ 的值。特别的,我们要在 $ch[x]$ 中插入或删除值 $0$ 。 + +参考代码: + +```cpp +// luogu-judger-enable-o2 +#include +#include +#include +#include +using namespace std; +const int maxn=100010; +const int inf=2e9; +int n,a,b,m,x,col[maxn]; +// 0 off 1 on +char op; +int cur,h[maxn*2],nxt[maxn*2],p[maxn*2]; +void add_edge(int x,int y) +{ + cur++; + nxt[cur]=h[x]; + h[x]=cur; + p[cur]=y; +} +bool vis[maxn]; +int rt,sum,siz[maxn],maxx[maxn],fa[maxn],dep[maxn]; +void calcsiz(int x,int f) +{ + siz[x]=1;maxx[x]=0; + for(int j=h[x];j;j=nxt[j])if(p[j]!=f&&!vis[p[j]]) + { + calcsiz(p[j],x); + siz[x]+=siz[p[j]]; + maxx[x]=max(maxx[x],siz[p[j]]); + } + maxx[x]=max(maxx[x],sum-siz[x]); + if(maxx[x]A,B;//heap=A-B + void insert(int x){A.push(x);} + void erase(int x){B.push(x);} + int top() + { + while(!B.empty()&&A.top()==B.top())A.pop(),B.pop(); + return A.top(); + } + void pop() + { + while(!B.empty()&&A.top()==B.top())A.pop(),B.pop(); + A.pop(); + } + int top2() + { + int t=top(),ret; + pop();ret=top(); + A.push(t); + return ret; + } + int size(){return A.size()-B.size();} +}dist[maxn],ch[maxn],ans; +void dfs(int x,int f,int d,heap&y) +{ + y.insert(d); + for(int j=h[x];j;j=nxt[j])if(p[j]!=f&&!vis[p[j]])dfs(p[j],x,d+1,y); +} +void pre(int x) +{ + vis[x]=true; + for(int j=h[x];j;j=nxt[j])if(!vis[p[j]]) + { + rt=0;maxx[rt]=inf;sum=siz[p[j]]; + calcsiz(p[j],-1);calcsiz(rt,-1); + fa[rt]=x; + dfs(p[j],-1,1,dist[rt]); + ch[x].insert(dist[rt].top()); + dep[rt]=dep[x]+1; + pre(rt); + } + ch[x].insert(0); + if(ch[x].size()>=2)ans.insert(ch[x].top()+ch[x].top2()); + else if(ch[x].size())ans.insert(ch[x].top()); +} +struct LCA +{ + int dep[maxn],lg[maxn],fa[maxn][20]; + void dfs(int x,int f) + { + for(int j=h[x];j;j=nxt[j])if(p[j]!=f) + dep[p[j]]=dep[x]+1,fa[p[j]][0]=x,dfs(p[j],x); + } + void init() + { + dfs(1,-1); + for(int i=2;i<=n;i++)lg[i]=lg[i/2]+1; + for(int j=1;j<=lg[n];j++)for(int i=1;i<=n;i++) + fa[i][j]=fa[fa[i][j-1]][j-1]; + } + int query(int x,int y) + { + if(dep[x]>dep[y])swap(x,y); + int k=dep[y]-dep[x]; + for(int i=0;k;k=k/2,i++)if(k&1)y=fa[y][i]; + if(x==y)return x; + k=dep[x]; + for(int i=lg[k];i>=0;i--)if(fa[x][i]!=fa[y][i])x=fa[x][i],y=fa[y][i]; + return fa[x][0]; + } + int dist(int x,int y){return dep[x]+dep[y]-2*dep[query(x,y)];} +}lca; +int d[maxn][20]; +int main() +{ + scanf("%d",&n); + for(int i=1;i=2)ans.erase(ch[x].top()+ch[x].top2()); + ch[x].erase(0); + if(ch[x].size()>=2)ans.insert(ch[x].top()+ch[x].top2()); + for(int i=x;fa[i];i=fa[i]) + { + if(ch[fa[i]].size()>=2)ans.erase(ch[fa[i]].top()+ch[fa[i]].top2()); + ch[fa[i]].erase(dist[i].top()); + dist[i].erase(d[x][dep[x]-dep[fa[i]]]); + if(dist[i].size())ch[fa[i]].insert(dist[i].top()); + if(ch[fa[i]].size()>=2)ans.insert(ch[fa[i]].top()+ch[fa[i]].top2()); + } + } + else + { + if(ch[x].size()>=2)ans.erase(ch[x].top()+ch[x].top2()); + ch[x].insert(0); + if(ch[x].size()>=2)ans.insert(ch[x].top()+ch[x].top2()); + for(int i=x;fa[i];i=fa[i]) + { + if(ch[fa[i]].size()>=2)ans.erase(ch[fa[i]].top()+ch[fa[i]].top2()); + if(dist[i].size())ch[fa[i]].erase(dist[i].top()); + dist[i].insert(d[x][dep[x]-dep[fa[i]]]); + ch[fa[i]].insert(dist[i].top()); + if(ch[fa[i]].size()>=2)ans.insert(ch[fa[i]].top()+ch[fa[i]].top2()); + } + } + col[x]^=1; + } + } + return 0; +} +``` +