[ BZOJ 4668 ] 冷战


\(\\\)

\(Description\)


\(N\)个点,开始没有边相连,进行按顺序给出的\(M\)个操作:

  • \(0\ u\ v\)\(u,v\)两点连一条边
  • \(1\ u\ v\) 查询\(u,v\)两点最早在第几条边连接的时候被连通

每次询问输出一个边的编号,强制在线。

  • \(N,M\in [1,5\times 10^5]\)

\(\\\)

\(Solution\)


在线并查集树上查询\(Lca\)

维护连通性的时候并查集不进行路径压缩,只进行按秩合并。考虑到并查集是树形结构,定义连通块的秩为块内树高\((\)其实定义为块的大小表现也不错\()\)。这样我们得到的是一棵真正的通过并集来连接的并查集树。

这棵树上有什么好的性质?答案是两点到\(Lca\)的路径上的边集,是真正将这两点连接起来的边集。也就是说,对于两点查询的答案,一定是两点到\(Lca\)路径上的最大边编号。

考虑如何求\(Lca\)。因为是在线,所以显然不能建立倍增数组等基于固定的树形态的做法。考虑暴力标记,先将两点跳到同一高度,再共同跳到\(Lca\)处既可,这样也能很方便的处理路径\(max\)的问题。

关于复杂度,其实它是合法的。根据按秩合并的原理,在查询连通块代表元素时复杂度是\(log\)级别的,同理都是跳父节点的过程,所以查询\(Lca\)复杂度也是\(log\)级别的。

\(\\\)

\(Code\)


并查集需要维护:当前节点深度,当前节点父节点编号,到父节点的边权,以及以当前节点为根子树大小。

注意当前节点深度这个部分,在查询\(Lca\)之前我们需要先更新一遍以确保深度是正确的,这个过程可以在查询代表元素的时候同时进行。

#include<cmath>
#include<cstdio>
#include<cctype>
#include<cstring>
#include<cstdlib>
#include<iostream>
#include<algorithm>
#define N 500010
#define R register
#define gc getchar
using namespace std;
 
int n,m,ans,cnt;
 
struct UFS{
  int f[N],g[N],d[N],sz[N];
 
  UFS(){for(R int i=1;i<N;++i)f[i]=i,d[i]=sz[i]=1;}
 
  int find(int x){
    if(x==f[x])return x;
    int ans=find(f[x]); d[x]=d[f[x]]+1; return ans;
  }
 
  inline void merge(int x,int y){
    int fx=find(x),fy=find(y);
    if(sz[fx]>sz[fy]) fx^=fy^=fx^=fy;
    sz[fy]+=sz[fx]; f[fx]=fy; g[fx]=cnt; d[fx]=d[fy]+1;
  }
 
  inline int lca(int x,int y){
    int ans=0;
    if(d[x]>d[y]) x^=y^=x^=y;
    while(d[y]>d[x]) ans=max(ans,g[y]),y=f[y];
    if(x==y) return ans;
    while(x!=y){
      ans=max(ans,max(g[x],g[y]));
      x=f[x]; y=f[y];
    }
    return ans;
  }
 
}ufs;
 
inline int rd(){
  int x=0; bool f=0; char c=gc();
  while(!isdigit(c)){if(c=='-')f=1;c=gc();}
  while(isdigit(c)){x=(x<<1)+(x<<3)+(c^48);c=gc();}
  return f?-x:x;
}
 
int main(){
  n=rd(); m=rd();
  for(R int i=1,op,x,y;i<=m;++i){
    op=rd(); x=rd()^ans; y=rd()^ans;
    if(op==0){
      ++cnt;
      if(ufs.find(x)!=ufs.find(y)) ufs.merge(x,y);
    }
    else if(ufs.find(x)!=ufs.find(y)){ans=0;puts("0");}
         else printf("%d\n",(ans=ufs.lca(x,y)));
  }
  return 0;
}
posted @ 2018-10-06 19:00  SGCollin  阅读(167)  评论(0编辑  收藏  举报