传送门 BZOJ 1095
大致题意
有一棵树,每个点是黑色或者白色,最开始全是黑点,有两种操作。
1 Get : 输出最远两个黑点之间的距离。
2 Change(x): 改变x号点的颜色。
动态点分治大法好,具体解法如下。
1. 构建 重心树
按照静态点分治的方法,记录每一个重心
x
的上一层重心··
对于一个重心
x
维护两个大根堆
f(x)
维护
x
为的子树中黑点到
g(x)
维护
x
的子树中黑点到
2.维护全局答案
全局答案也用一个堆
3.修改
- 对一个点
x
的修改,只会影响重心树上的祖先节点的堆,顺着
par(x) 遍历即可。 - 对一个
x
的祖先节点
v ,要从 f(v) 中 删去 dist(x,par(v)) 。 - f(v) 改变可能会导致 g(par(v))的 改变 所以先从 g(par(v)) 中删掉 f(v).top 修-改 完 f(v) 后在将新的 f(v).top 加入 g(par(v)) 。
- 类似的, g(par(v)) 的改变对全局答案 Q <script type="math/tex" id="MathJax-Element-90">Q</script> 也会有影响,处理方法和上面一样。
4.数据结构
从之前的分析可以知道,这道题中用到的堆需要支持插入和删除键值(可删除的堆),这当然可以用两个堆实现。
5. 代码
/**************************************************************
Problem: 1095
User: spark
Language: C++
Result: Accepted
Time:15132 ms
Memory:155180 kb
****************************************************************/
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<queue>
using namespace std;
const int maxn = 200000+5;
const int inf= 0x3f3f3f3f;
template<class T>
inline void _read(T& x){
char ch= getchar(); bool mark=false;
for(;!isdigit(ch);ch=getchar()) if(ch=='-') mark=true;
for(x=0;isdigit(ch);ch= getchar()) x= x*10+ch-'0';
if(mark) x=-x;
}
char ch[50];
template <class T>
inline void _put(T x){
if(!x){putchar('0');return ;}
if(x<0) x=-x,putchar('-');
int rear=0;
while(x)ch[++rear]='0'+x%10,x/=10;
while(rear) putchar(ch[rear--]);
}
inline int _log(int x){int k=0;while((1<<(k+1)<=x))k++; return k;}
struct Heap{
priority_queue<int> q,del;
int top(){
while(!q.empty() && !del.empty() && q.top()==del.top())
q.pop(),del.pop();
return q.empty()? -1:q.top();
}
void pop(){
top();
if(!q.empty()) q.pop();
}
int Second(){
int x= top();
pop();
int ret= top(); q.push(x);
return ret;
}
void push(int x){q.push(x);}
void Delete(int x){del.push(x);}
int size(){return q.size()-del.size();}
}f[maxn],ans,g[maxn];
int S,e,Last[maxn],Next[maxn],To[maxn],dep[maxn],size[maxn],maxsize[maxn];
int n,qq,tot,BlackCnt,par[maxn],black[maxn];
bool del[maxn];
struct TreeGraph{
int fa[maxn][20];
void Addedge(int x,int y){
To[++e] = y; Next[e]=Last[x]; Last[x]=e;
To[++e] = x; Next[e]=Last[y]; Last[y]=e;
}
void DFS(int x,int father){
size[x]=1;
dep[x]=dep[father]+1;
fa[x][0]= father;
int k = _log(dep[x]);
for(int i=1;i<=k;i++) fa[x][i]= fa[fa[x][i-1]][i-1];
for(int i=Last[x];i;i=Next[i]){
int s=To[i];
if(s==father) continue;
DFS(s,x);
size[x]+=size[s];
}
}
int LCA(int x,int y){
if(dep[x]<dep[y]) swap(x,y);
int i,p=dep[x]-dep[y];
for(i=0;i<=S;i++)
if((p>>i)&1) x= fa[x][i];
if(x==y) return x;
int k = _log(dep[x]);
for(i=S;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[LCA(x,y)];}
}T;
int Q[maxn],dfs_clock;
void DFS(int x,int father){
Q[++dfs_clock] = x;
maxsize[x]= size[x] =1;
for(int i=Last[x];i;i=Next[i]){
int s= To[i];
if(s==father || del[s]) continue;
DFS(s,x);
size[x]+=size[s];
maxsize[x] = max(maxsize[x],size[s]);
}
}
int Centroid(int x){
dfs_clock=0;
DFS(x,0);
int ret=0,Min=inf;
for(int i=1;i<=dfs_clock;i++){
//cout<<"i: "<<i<<" Max: "<<maxsize[i]<<endl;
maxsize[Q[i]]= max(maxsize[Q[i]],size[x]-size[Q[i]]);
if(maxsize[Q[i]]<Min) Min=maxsize[Q[i]],ret=Q[i];
}
return ret;
}
void Build_Heap(int x,int father,int center){
//cout<<"Build_Heap: "<<x<<" "<<center<<endl;
f[center].push(T.dist(x,par[center]));
for(int i=Last[x];i;i=Next[i])
if(!del[To[i]] && To[i]!=father)
Build_Heap(To[i],x,center);
}
int Divide(int x,int father){
x= Centroid(x);
//cout<<"Centriod: "<<x<<endl;
del[x]= true;
par[x]= father;
if(father) Build_Heap(x,0,x);
if(f[x].size()) g[father].push(f[x].top());
tot--;
for(int i=Last[x];i;i=Next[i])
if(!del[To[i]])
Divide(To[i],x);
}
void UpdateAns(Heap& h,int type){
if(h.size()>=2){
//cout<<" UpdateAns: "<<h.top()+h.Second()<<" "<<type<<endl;
if(type== 1) ans.push(h.top()+h.Second());
else ans.Delete(h.top()+h.Second());
}
}
void Change(int x){
if(black[x]){
BlackCnt--;
for(int i=x;par[i];i=par[i]){
UpdateAns(g[par[i]],-1);
if(f[i].size())g[par[i]].Delete(f[i].top());
f[i].Delete(T.dist(x,par[i]));
if(f[i].size()) g[par[i]].push(f[i].top());
UpdateAns(g[par[i]],1);
}
}
else {
BlackCnt++;
for(int i=x;par[i];i=par[i]){
UpdateAns(g[par[i]],-1);
if(f[i].size()) g[par[i]].Delete(f[i].top());
f[i].push(T.dist(x,par[i]));
g[par[i]].push(f[i].top());
UpdateAns(g[par[i]],1);
}
}
black[x]^=1;
}
int main(){
int i,j,x,y;
_read(n);
tot = BlackCnt = n ;
S= _log(n);
for(i=1;i<n;i++){
_read(x); _read(y);
T.Addedge(x,y);
}
T.DFS(1,0);
Divide(1,0);
for(i=1;i<=n;i++){
UpdateAns(g[i],1);
black[i]=1;
}
_read(qq);
while(qq--){
char cmd = getchar();
while(!isalpha(cmd)) cmd= getchar();
if(cmd=='G'){
if(!BlackCnt) puts("-1");
else if(BlackCnt==1) puts("0");
else _put(ans.top()),putchar('\n');
}
else {
_read(x);
Change(x);
}
}
return 0;
}