在查询和修改的时候,我们在点分树上暴力跳父亲修改。由于点分树的深度最多是 $O(\log_2 n)$ 的,所以这样做复杂度能得到保证。
-在动态点分治的过程中,需要一个结点到其点分树上的祖先的距离等其他信息,由于一个点最多有 $O(\log_2 n)$ 个祖先,我们可以在计算点分树时额外计算深度 ```dep[x]``` 或使用 LCA ,预处理出这些距离或实现实时查询。
+在动态点分治的过程中,需要一个结点到其点分树上的祖先的距离等其他信息,由于一个点最多有 $O(\log_2 n)$ 个祖先,我们可以在计算点分树时额外计算深度 $dep[x]$ 或使用 LCA ,预处理出这些距离或实现实时查询。
在动态点分治的过程中,一个结点在其点分树上的祖先结点的信息中可能会被重复计算,这是我们需要消去重复部分的影响。一般的方法是对于一个联通块用两种方式记录:一个是其到分治中心的距离信息,另一个是其到点分树上分治中心父亲的距离信息。这一部分内容将在例题中得到展现。
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<cstdio>
+#include<cstring>
+#include<algorithm>
+#include<queue>
+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]<maxx[rt])rt=x;
+}
+struct heap
+{
+ priority_queue<int>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<n;i++)scanf("%d%d",&a,&b),add_edge(a,b),add_edge(b,a);
+ lca.init();
+ rt=0;maxx[rt]=inf;sum=n;calcsiz(1,-1);calcsiz(rt,-1);pre(rt);
+ //for(int i=1;i<=n;i++)printf("%d ",fa[i]);printf("\n");
+ for(int i=1;i<=n;i++)for(int j=i;j;j=fa[j])d[i][dep[i]-dep[j]]=lca.dist(i,j);
+ scanf("%d",&m);
+ while(m--)
+ {
+ scanf(" %c",&op);
+ if(op=='G')
+ {
+ if(ans.size())printf("%d\n",ans.top());
+ else printf("-1\n");
+ }
+ else
+ {
+ scanf("%d",&x);
+ if(!col[x])
+ {
+ if(ch[x].size()>=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;
+}
+```
+