bzoj4668 冷战

题目

好久没写blog了,可能是因为最近比较忙吧,距离noip2017也就60个小时左右了吧。

要开始复习一下模板了。

这道题问是否联通,显然要用并查集来做,但是,是否能路径合并呢?
简单想一想,当然不能啦,因为我们每个结点上要记录一个时间标记,然后构成一个像树一样的结构(当然可能有其它做法)。

但是,裸的并查集会超时的,如何优化呢?

并查集主要优化就两个:路径压缩和按秩合并,前者接近O(n),后者能让高度变小,但我也不知道具体是多少,大概logn?

所以,我们就按秩合并一下就可以过了。

什么是按秩合并?我也不太清楚真正的,网上的说法也太多,我的意思就是记录一下每个集合的元素个数,合并时,小的接在大的上。

询问的话,朴素的来,就是树上路径求一个最大值。
先处理深度,再类似lca一个一个跳。

#include<bits/stdc++.h>
#define N 500000
#define Max(a,b,c) max(max(a,b),c)
using namespace std;
int n,m,x,y,opt,last,fx,fy,T;
int f[N+5],v[N+5],siz[N+5],dep[N+5];
inline char nc()
{
    static char buf[100000],*p1=buf,*p2=buf;
    return p1==p2&&(p2=(p1=buf)+fread(buf,1,100000,stdin),p1==p2)?EOF:*p1++;
}
inline int read()
{
    int x=0,b=1;
    char c=nc();
    for(;!(c<='9'&&c>='0');c=nc())if(c=='-')b=-1;
    for(;c<='9'&&c>='0';c=nc())x=x*10+c-'0';
    return x*b;
}
inline int find(int x)
{
    return x==f[x]?f[x]:find(f[x]);
}
inline void pre(int x)
{
    if(x==f[x])return;
    pre(f[x]);
    dep[x]=dep[f[x]]+1;
}
inline int ask(int x,int y)
{
    pre(x),pre(y);
    if(dep[x]<dep[y])swap(x,y);
    int mx=0;
    while(dep[x]>dep[y]&&x!=y)mx=max(mx,v[x]),x=f[x];
    while(x!=y)mx=Max(mx,v[x],v[y]),x=f[x],y=f[y];
    return mx;
}
int main()
{
    freopen("in.txt","r",stdin);
    n=read(),m=read();
    for(int i=1;i<=n;i++)f[i]=i,siz[i]=1;
    for(int i=1;i<=m;i++)
    {
        opt=read(),x=read(),y=read();
        x^=last,y^=last;
        if(opt==0)
        {
            fx=find(x),fy=find(y);
            T++;
            if(fx==fy)continue;
            if(siz[fx]>siz[fy])swap(fx,fy);
            f[fx]=fy;
            siz[fy]+=siz[fx];
            v[fx]=T;
        }
        else
        {
            fx=find(x),fy=find(y);
            if(fx!=fy)printf("%d\n",last=0);
            else printf("%d\n",last=ask(x,y));
        }
    }
    return 0;
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值