zoukankan      html  css  js  c++  java
  • [BZOJ4668]冷战(并查集)

    比较自然的思路是,由于需要记录连通块合并时的信息,所以需要建出Kruskal重构树。

    需要用LCT维护,支持加点和在线LCA操作。

    不妨考虑在并查集合并的同时记录信息,pre[x]表示x与它的父亲相连的时刻。

    两个点连通的时刻,等于两个点之间路径上时刻的最大值。

    注意到按秩合并但不路径压缩的并查集不改变树的结构,且树高为log,正好符合要求。

    $O(nlog n)$

     1 #include<cstdio>
     2 #include<algorithm>
     3 #define rep(i,l,r) for (int i=(l); i<=(r); i++)
     4 using namespace std;
     5 
     6 const int N=1000010;
     7 int n,m,op,u,v,ans,tim,he[N],fa[N],pre[N];
     8 
     9 int find(int x){ return (fa[x]==x) ? x : find(fa[x]); }
    10 
    11 void uni(int u,int v,int tim){
    12     u=find(u); v=find(v);
    13     if (u==v) return;
    14     if (he[u]<he[v]) swap(u,v);
    15     fa[v]=u; pre[v]=tim;
    16     if (he[u]==he[v]) he[u]++;
    17 }
    18 
    19 int lca(int u,int v){
    20     if (find(u)!=find(v)) return 0;
    21     int s1=0,s2=0,x=u,y=v,res=0;
    22     while (x!=fa[x]) s1++,x=fa[x];
    23     while (y!=fa[y]) s2++,y=fa[y];
    24     while (s1>s2) res=max(res,pre[u]),u=fa[u],s1--;
    25     while (s2>s1) res=max(res,pre[v]),v=fa[v],s2--;
    26     while (u!=v) res=max(res,max(pre[u],pre[v])),u=fa[u],v=fa[v];
    27     return res;
    28 }
    29 
    30 int main(){
    31     freopen("bzoj4668.in","r",stdin);
    32     freopen("bzoj4668.out","w",stdout);
    33     scanf("%d%d",&n,&m);
    34     rep(i,1,n) fa[i]=i,he[i]=1;
    35     rep(i,1,m){
    36         scanf("%d%d%d",&op,&u,&v); u^=ans; v^=ans;
    37         if (op==0) uni(u,v,++tim); else printf("%d
    ",ans=lca(u,v));
    38     }
    39     return 0;
    40 }
  • 相关阅读:
    0802作业1替换文本文件内容

    看病
    爬山
    作业1
    超市(未完成)
    图片复制
    替换
    文件
    英文字母和中文汉字在不同字符集编码下的字节数
  • 原文地址:https://www.cnblogs.com/HocRiser/p/10098620.html
Copyright © 2011-2022 走看看