BZOJ 1095: [ZJOI2007]Hide 捉迷藏

时间:2022-04-12 21:03:18

Description

一棵树,支持两个操作,修改一个点的颜色,问树上最远的两个白点距离.

Sol

动态点分治.

动态点分治就是将每个重心连接起来,形成一个跟线段树类似的结构,当然它不是二叉的...

这样的树一共有 \(logn\) 层,每个节点维护一些信息.

s1[] 所有子节点到该节点的父重心,也就是上一个重心,所有距离的集合,需要满足插入删除询问最大值的操作,这里我直接用的multiset.

s2[] 所有子重心,就是下面一层的重心,到这个点的最大值分别是多少,需要满足插入删除询问最大值的操作,这里我直接用set.

S答案集合,过所有重心的最长链的集合,就是所有子重心到他的最大值+次大值,需要满足插入删除询问最大值的操作,这里我直接用set.

再加上一个 \(O(1)\) LCA来求一下距离.

这样第一次预处理的时候处理完所有事情,数据修改的时候呢...我的做法比较蠢但是好写,不用考虑那么多乱七八糟的东西..

直接求出整个链,因为一个点对下面的点是没有贡献的,直接向上找出来这一条由重心连成的链.

然后先删掉所有这个节点可能产生的贡献,修改,再重新统计这些节点的最大值..插入同理...

这样复杂度就变成了 \(O(nlog^2n)\) 数据结构有一个 \(log\) ,点分治有一个 \(log\) 修改也是 \(log^2\) 的

打着打着发现自己代码到了6K...其实很大一部分都是调试信息...

Code

/**************************************************************
Problem: 1095
User: BeiYu
Language: C++
Result: Accepted
Time:31445 ms
Memory:78796 kb
****************************************************************/ #include <bits/stdc++.h>
using namespace std; #define debug(a) cout<<#a<<"="<<a<<" "
#define mpr make_pair
typedef pair< int,int > pr;
const int N = 1e5+50;
const int M = 25; int n,m,k,rt,cw;
vector< pr > g[N];
int t[N],sz[N],ud[N],cl[N],frt[N]; set< pr,greater< pr > > S;
multiset< int,greater< int > > s1[N];
set< pr,greater< pr > > s2[N]; inline int in(int x=0,char ch=getchar()) { while(ch>'9' || ch<'0') ch=getchar();
while(ch>='0' && ch<='9') x=x*10+ch-'0',ch=getchar();return x; }
inline char getc(char ch=getchar()) { while(ch>'Z' || ch<'A') ch=getchar();return ch; } void Print(set< pr,greater< pr > > &S) {
cout<<"--------start------------"<<endl;
for(set< pr >::iterator i=S.begin();i!=S.end();i++)
cout<<"("<<(*i).first<<" "<<(*i).second<<") ";
cout<<endl<<"----------over-----------"<<endl;
}
void Print(multiset< int,greater< int > > &S) {
cout<<"--------start------------"<<endl;
for(multiset< int >::iterator i=S.begin();i!=S.end();i++)
cout<<(*i)<<" ";
cout<<endl<<"----------over-----------"<<endl;
}
void SuperPrint() {
for(int i=1;i<=n;i++) cout<<frt[i]<<" ";cout<<endl; for(int i=1;i<=n;i++) cout<<i<<endl<<"--> s1[]"<<endl,Print(s1[i]),cout<<"--> s2[]"<<endl,Print(s2[i]); cout<<"--> S"<<endl;
Print(S);
}
void AddEdge(int fr,int to,int w) { g[fr].push_back(mpr(to,w)); } struct Tree {
int dp[N],ds[N],fw[N],ct;
int lg[N<<1],rq[N<<1][M],pow2[M]; void DFS(int u,int fa,int w) {
fw[u]=++ct,dp[u]=dp[fa]+1,rq[ct][0]=u,ds[u]=w;
for(int i=0,v;i<(int)g[u].size();i++)
if((v=g[u][i].first)!=fa) DFS(v,u,w+g[u][i].second),rq[++ct][0]=u;
}
void init() {
DFS(1,1,0);
pow2[0]=1;for(int i=1;i<M;i++) pow2[i]=pow2[i-1]<<1;
lg[0]=-1;for(int i=1;i<=ct;i++) lg[i]=lg[i>>1]+1;
for(int j=1;j<M;j++) for(int i=1;i<=ct;i++) if(i+pow2[j]-1<=ct){
int u=rq[i][j-1],v=rq[i+pow2[j-1]][j-1];
if(dp[u]<dp[v]) rq[i][j]=u;else rq[i][j]=v;
}
}
int Dis(int u,int v) {
if(fw[u]>fw[v]) swap(u,v);
int lg2=lg[fw[v]-fw[u]+1];
int lca=dp[rq[fw[u]][lg2]]<dp[rq[fw[v]-pow2[lg2]+1][lg2]] ? rq[fw[u]][lg2] : rq[fw[v]-pow2[lg2]+1][lg2];
return ds[u]+ds[v]-2*ds[lca];
}
}qt; int dis(int u,int v) { return qt.Dis(u,v); } void GetRoot(int u,int fa,int nn) {
sz[u]=1,t[u]=0;
for(int i=0,v;i<(int)g[u].size();i++)
if((v=g[u][i].first)!=fa && !ud[v])
GetRoot(v,u,nn),sz[u]+=sz[v],t[u]=max(t[u],sz[v]);
t[u]=max(t[u],nn-sz[u]);
if(t[u]<t[rt]) rt=u;
} void GetDis(int u,int fa,int ff,int spf) {
if(spf) s1[ff].insert(dis(u,spf));
for(int i=0,v;i<(int)g[u].size();i++)
if((v=g[u][i].first)!=fa && !ud[v]) GetDis(v,u,ff,spf);
} pr Getv(int x) {
if(s2[x].size()<2) return mpr(-1,-1);
else return mpr((*s2[x].begin()).first+(*(++s2[x].begin())).first,x);
} void GetAns(int u,int nn) {
ud[u]=1;
if(frt[u]) s1[u].insert(dis(u,frt[u]));s2[u].insert(mpr(0,u));
for(int i=0,v;i<(int)g[u].size();i++) if(!ud[v=g[u][i].first]) {
GetDis(v,u,u,frt[u]);
}
for(int i=0,v,ss;i<(int)g[u].size();i++) if(!ud[v=g[u][i].first]) {
rt=0,ss=sz[u]>sz[v]?sz[v]:nn-sz[u];
GetRoot(v,v,ss),frt[rt]=u,v=rt,GetAns(rt,ss);
s2[u].insert(mpr(*s1[v].begin(),v));
}
S.insert(Getv(u));
} //S All
//s1 son->father'sfather
//s2 sonmax
void Modify(int x) {
if(cl[x]) cw++;else cw--;
vector< int > tmp;
for(int i=x;i;i=frt[i]){ tmp.push_back(i); }
// for(int i=0;i<(int)tmp.size();i++) cout<<tmp[i]<<" ";cout<<endl;
if(cl[x]) {
for(int i=0;i<(int)tmp.size();i++) S.erase(Getv(tmp[i]));
for(int i=0;i<(int)tmp.size();i++) {
// if(!i) s2[tmp[i]].erase(mpr(0,tmp[i]));
// else
if(i && !s1[tmp[i-1]].empty()) s2[tmp[i]].erase(mpr(*s1[tmp[i-1]].begin(),tmp[i-1]));
}
for(int i=0;i<(int)tmp.size();i++) s1[tmp[i]].insert(dis(x,frt[tmp[i]]));
for(int i=0;i<(int)tmp.size();i++) {
if(!i) s2[tmp[i]].insert(mpr(0,tmp[i]));
else s2[tmp[i]].insert(mpr(*s1[tmp[i-1]].begin(),tmp[i-1]));
}
for(int i=0;i<(int)tmp.size();i++) S.insert(Getv(tmp[i])); }else {
for(int i=0;i<(int)tmp.size();i++) S.erase(Getv(tmp[i]));
// cout<<"--> S"<<endl;Print(S);
for(int i=0;i<(int)tmp.size();i++) {
if(!i) s2[tmp[i]].erase(mpr(0,tmp[i]));
else s2[tmp[i]].erase(mpr(*s1[tmp[i-1]].begin(),tmp[i-1]));
}
// cout<<"--> s2[1]"<<endl;Print(s2[1]);
// cout<<"--> s2[3]"<<endl;Print(s2[3]); for(int i=0;i<(int)tmp.size();i++) if(frt[tmp[i]]) s1[tmp[i]].erase(s1[tmp[i]].find(dis(x,frt[tmp[i]])));
for(int i=0;i<(int)tmp.size();i++) {
// if(!i) s2[tmp[i]].insert(mpr(0,tmp[i]));
// else
if(i && !s1[tmp[i-1]].empty()) s2[tmp[i]].insert(mpr(*s1[tmp[i-1]].begin(),tmp[i-1]));
}
// cout<<"--> s2[1]"<<endl;Print(s2[1]);
for(int i=0;i<(int)tmp.size();i++) S.insert(Getv(tmp[i]));
}cl[x]^=1;
} void init() {
cw=n=in();
for(int i=1,u,v,w;i<n;i++) u=in(),v=in(),w=1,AddEdge(u,v,w),AddEdge(v,u,w);
// for(int i=1,u,v,w;i<n;i++) u=in(),v=in(),w=in(),AddEdge(u,v,w),AddEdge(v,u,w);
qt.init();
t[0]=N;
GetRoot(1,1,n);
GetAns(rt,n);
} int main() {
// freopen("in.in","r",stdin);
init(); // SuperPrint(); // Print(S);
for(int q=in();q--;) {
// cout<<"QAQ"<<endl<<endl;
if(getc()=='C') {
int x=in();Modify(x);
// cout<<"--> S"<<endl;Print(S);
// cout<<"--> s1[3]"<<endl;Print(s1[3]);
// cout<<"--> s2[3]"<<endl;Print(s2[3]);
// SuperPrint();
}else {
if(!cw) puts("-1");
else if(cw==1) puts("0");
else printf("%d\n",(*S.begin()).first);
}
}
return 0;
}