码迷,mamicode.com
首页 > 其他好文 > 详细

P2056 [ZJOI2007]捉迷藏

时间:2019-08-31 10:52:07      阅读:68      评论:0      收藏:0      [点我收藏+]

标签:namespace   ini   zjoi2007   put   数据结构   产生   记录   top   ++i   

思路:动态点分治

提交:3次

错因:在加点的时候堆的操作错误。

题解:

为什么有时候说点分治是一种数据结构呢?我觉得是因为点分治的核心是在分治过程中产生的树形结构,即点分树,它的深度是 \(\log\) 级别的。
对于这道题,我们首先要建立出来点分树(只记father),每个点维护所有孩子的答案。当修改时,我们暴力跳点分树上的father(仍是 \(\log\) 级别的)。
如何维护信息呢?我们开三种堆:一个堆维护自己子树中的路径长度dis;再用一个堆维护每个孩子dis的堆顶,记为ch,显然,经过这个点的最长路径为堆顶和次堆顶(最大和次大);再用一个堆记录一个全局答案。
删点时(设为 \(u\) ),我们先把之前的答案从全局堆中去掉,然后删掉路径长度为0的点,再尝试将答案加回全局堆。然后跳father,在堆中删掉对应的距离 \(len(u,x)\)

代码:

#include<bits/stdc++.h>
#define R register int
using namespace std;
namespace Luitaryi {
template<class I> inline I g(I& x) { x=0; register I f=1;
  register char ch; while(!isdigit(ch=getchar())) f=ch=='-'?-1:f;
  do x=x*10+(ch^48); while(isdigit(ch=getchar())); return x*=f;
} const int N=100010,M=500010,Inf=0x3f3f3f3f;
int n,m,cnt,sum,rt; bool vis[N];
int vr[N<<1],nxt[N<<1],fir[N],sz[N],mx[N],d[N],c[N],fa[N],len[20][N];
inline void add(int u,int v) {
  vr[++cnt]=v,nxt[cnt]=fir[u],fir[u]=cnt;
  vr[++cnt]=u,nxt[cnt]=fir[v],fir[v]=cnt;
}
struct heap {
  priority_queue<int> dat,dst;
  inline void ins(int x) {dat.push(x);}
  inline void del(int x) {dst.push(x);}
  inline int top() {
    while(dst.size()&&dat.top()==dst.top()) dat.pop(),dst.pop();
    return dat.top();
  }
  inline void pop() {
    while(dst.size()&&dat.top()==dst.top()) dat.pop(),dst.pop(); dat.pop();
  }
  inline int rtop() {
    R t=top(),ret; pop();
    ret=top(); dat.push(t); return ret;
  }
  inline int size() {return dat.size()-dst.size();}
}dis[N],ch[N],ans;
inline void getsz(int u,int fa) {
  sz[u]=1,mx[u]=0; 
  for(R i=fir[u];i;i=nxt[i]) { R v=vr[i];
    if(v==fa||vis[v]) continue;
    getsz(v,u),sz[u]+=sz[v];
    mx[u]=max(mx[u],sz[v]); 
  } mx[u]=max(mx[u],sum-sz[u]);
  if(mx[u]<mx[rt]) rt=u;
}
inline void dfs(int u,int fa,int s,heap& q) {
  q.ins(s); for(R i=fir[u];i;i=nxt[i]) { R v=vr[i];
    if(v==fa||vis[v]) continue; dfs(v,u,s+1,q);
  }
}
inline void pre(int u) { vis[u]=true;
  for(R i=fir[u];i;i=nxt[i]) { R v=vr[i];
    if(vis[v]) continue;
    sum=sz[v],rt=0,mx[0]=Inf;
    getsz(v,-1),getsz(rt,-1); fa[rt]=u; 
    dfs(v,-1,1,dis[rt]); ch[u].ins(dis[rt].top());
    d[rt]=d[u]+1; pre(rt);
  } ch[u].ins(0); if(ch[u].size()>=2) ans.ins(ch[u].top()+ch[u].rtop());
  else if(ch[u].size()) ans.ins(ch[u].top());
}
namespace lca {
int d[N],lg[N],f[20][N];
inline void dfs(int u,int fa) {
  for(R i=fir[u];i;i=nxt[i]) { R v=vr[i];
    if(v==fa) continue;
    d[v]=d[u]+1; f[0][v]=u; dfs(v,u);
  }
}
inline void init() {
  dfs(1,-1); for(R i=2;i<=n;++i) lg[i]=lg[i>>1]+1;
  for(R i=1;i<=lg[n];++i) for(R j=1;j<=n;++j)
    f[i][j]=f[i-1][f[i-1][j]];
}
inline int query(int u,int v) { if(d[u]<d[v]) swap(u,v); 
  for(R k=lg[d[u]];~k;--k) if(d[f[k][u]]>=d[v]) u=f[k][u];
  if(u==v) return u; 
  for(R k=lg[d[u]];~k;--k) if(f[k][u]!=f[k][v]) u=f[k][u],v=f[k][v];
  return f[0][u];
}
inline int dis(int u,int v) {return d[u]+d[v]-2*d[query(u,v)];}
}
inline void main() {
  g(n); for(R i=1,u,v;i<n;++i) g(u),g(v),add(u,v);
  lca::init(); rt=0; mx[rt]=Inf; sum=n; getsz(1,-1),getsz(rt,-1),pre(rt);
  for(R u=1;u<=n;++u) for(R i=u;i;i=fa[i]) len[d[u]-d[i]][u]=lca::dis(u,i);
  g(m); while(m--) { register char s[2]; scanf("%s",s);
    if(s[0]=='G') if(ans.size()) printf("%d\n",ans.top()); else puts("-1");
    else { R u; g(u); 
      if(!c[u]) {
        if(ch[u].size()>=2) ans.del(ch[u].top()+ch[u].rtop());
        ch[u].del(0); if(ch[u].size()>=2) ans.ins(ch[u].top()+ch[u].rtop());
        for(R i=u;fa[i];i=fa[i]) {
          if(ch[fa[i]].size()>=2) ans.del(ch[fa[i]].top()+ch[fa[i]].rtop());
          ch[fa[i]].del(dis[i].top());
          dis[i].del(len[d[u]-d[fa[i]]][u]);
          if(dis[i].size()) ch[fa[i]].ins(dis[i].top());
          if(ch[fa[i]].size()>=2) ans.ins(ch[fa[i]].top()+ch[fa[i]].rtop());
        }
      } else {
        if(ch[u].size()>=2) ans.del(ch[u].top()+ch[u].rtop());
        ch[u].ins(0); if(ch[u].size()>=2) ans.ins(ch[u].top()+ch[u].rtop());
        for(R i=u;fa[i];i=fa[i]) {
          if(ch[fa[i]].size()>=2) ans.del(ch[fa[i]].top()+ch[fa[i]].rtop());
          if(dis[i].size()) ch[fa[i]].del(dis[i].top());
          dis[i].ins(len[d[u]-d[fa[i]]][u]);
          ch[fa[i]].ins(dis[i].top());
          if(ch[fa[i]].size()>=2) ans.ins(ch[fa[i]].top()+ch[fa[i]].rtop());
        }
      } c[u]^=1;
    }
  } 
}
} signed main() {Luitaryi::main(); return 0;}

2019.08.31
69

P2056 [ZJOI2007]捉迷藏

标签:namespace   ini   zjoi2007   put   数据结构   产生   记录   top   ++i   

原文地址:https://www.cnblogs.com/Jackpei/p/11437901.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!