HHHOJ#143——并查集离线+树链剖分

这是一道嘿嘿嘿OJ的题目,内部资料,所以没有题面。
这道题是LCT的板子题,但是蒟蒻不会LCT,所以只能用它的弱化版树剖来做了。
我们先离线读入所有的操作,对于操作1,我们先连边,并打标记,如果find(x)==find(y),则在后面的操作就不许要管了,直接continue。对于操作2,我们就判断x和y是否在同一个并查集中,如果不在就打标记,后面操作时直接输-1。
这样离线之后就可以用树剖来维护了,对于操作1,我们只需要对线段树里的点进行单点修改即可。操作2就是查询树链u,v上所有的颜色。由于颜色只有60种,所以我们直接用一个60位的二进制数来存,在线段树里用或(|)运算即可。

Code:

#include<bits/stdc++.h>
#define MAXN 200005
#define ll long long
using namespace std;
ll read(){
    char c;ll x;while(c=getchar(),c<'0'||c>'9');x=c-'0';
    while(c=getchar(),c>='0'&&c<='9') x=x*10+c-'0';return x;
}
ll n,q,cnt,dfn,head[MAXN],nxt[MAXN],go[MAXN],vis[MAXN*3],val[MAXN],rt;
ll sum[MAXN*4],son[MAXN],siz[MAXN],dep[MAXN],fa[MAXN],rank[MAXN],tid[MAXN],top[MAXN];
struct node{
    ll type,x,y;
}Q[MAXN*3];
ll find(ll x){
    if(fa[x]!=x) fa[x]=find(fa[x]);
    return fa[x];
}
void unionn(ll x,ll y){
    x=find(x);y=find(y);
    fa[y]=x;
}
void addedge(ll x,ll y){
    go[cnt]=y;nxt[cnt]=head[x];head[x]=cnt;cnt++;
    go[cnt]=x;nxt[cnt]=head[y];head[y]=cnt;cnt++;
}
void dfsI(ll x,ll father){
    fa[x]=father;dep[x]=dep[father]+1;
    siz[x]=1;son[x]=-1;
    for(ll i=head[x];i!=-1;i=nxt[i]){
        ll to=go[i];
        if(to==fa[x]) continue;
        dfsI(to,x);siz[x]+=siz[to];
        if(son[x]==-1||siz[to]>siz[son[x]]) son[x]=to;
    }
}
void dfsII(ll x,ll t){
    top[x]=t;tid[x]=++dfn;rank[dfn]=val[x];
    if(son[x]==-1) return;
    dfsII(son[x],t);
    for(ll i=head[x];i!=-1;i=nxt[i]){
        ll to=go[i];
        if(to==fa[x]||to==son[x]) continue;
        dfsII(to,to);
    }
}
void up(ll node){sum[node]=sum[node<<1]|sum[node<<1|1];}
void build(ll node,ll l,ll r){
    if(l==r){
        sum[node]=1ll*1<<(rank[l]-1);return;
    }
    ll mid=(l+r)>>1;
    build(node<<1,l,mid);
    build(node<<1|1,mid+1,r);
    up(node);
}
void update(ll node,ll l,ll r,ll p,ll ad){
    if(l==r){
        sum[node]=1ll*1<<(ad-1);return;
    }
    ll mid=(l+r)>>1;
    if(p<=mid) update(node<<1,l,mid,p,ad);
    else update(node<<1|1,mid+1,r,p,ad);
    up(node);
}
ll query(ll node,ll l,ll r,ll L,ll R){
    if(L<=l&&r<=R){
        return sum[node];
    }
    ll mid=(l+r)>>1,res=0;
    if(L<=mid) res|=query(node<<1,l,mid,L,R);
    if(R>mid) res|=query(node<<1|1,mid+1,r,L,R);
    return res;
}
ll queryLINK(ll u,ll v){
    ll res=0,tot=0;
    while(top[u]!=top[v]){
        if(dep[top[u]]>dep[top[v]]) swap(u,v);
        res|=query(1,1,n,tid[top[v]],tid[v]);
        v=fa[top[v]];
    }
    if(dep[u]>dep[v]) swap(u,v);
    res|=query(1,1,n,tid[u],tid[v]);
    while(res){if(res&1) tot++;res/=2;}
    return tot;
}
int main()
{
    memset(head,-1,sizeof(head));
    n=read();q=read();
    for(ll i=1;i<=n;i++) val[i]=read();
    for(ll i=1;i<=n;i++) fa[i]=i;
    for(ll i=1;i<=q;i++){
        ll type=read(),x=read(),y=read();
        Q[i]=(node){type,x,y};
        if(type==1){
            if(find(x)==find(y)){vis[i]=1;continue;}
            unionn(x,y);addedge(x,y);
        }
        if(type==2){
            if(find(x)!=find(y)) vis[i]=1;
        }
    }
    dfsI(1,0);
    dfsII(1,1);
    build(1,1,n);
    for(ll i=1;i<=q;i++){
        if(Q[i].type==1){
            if(vis[i]) continue;
            ll mid=(val[Q[i].x]+val[Q[i].y])/2;
            val[Q[i].x]=mid;val[Q[i].y]=mid;
            update(1,1,n,tid[Q[i].x],mid);
            update(1,1,n,tid[Q[i].y],mid);
        }
        if(Q[i].type==2){
            if(vis[i]) puts("-1");
            else printf("%lld\n",queryLINK(Q[i].x,Q[i].y));
        }
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/stevensonson/article/details/80245235
今日推荐