Luogu4172 [WC2006]水管局长

https://www.luogu.com.cn/problem/P4172

\(LCT\)动态维护最小生成树裸题,但是我用了指针版\(LCT\)\(RE\)到飞起

考虑这道题是删边,我们可以改成加边进行操作,边权仍然可以按照套路链一个点当做边

为了防止访问空指针,我们可以把根节点的父亲指向一个结构体\(rt\)

注意,那些会改变原指针的函数不能使用\(*\&x\),只能用\(*x\),否则会把原来的指针指向变掉

这次\(findroot\)写挂了,下次小心点

当然\(connect,update,push\_rev\)等处都需要特判空指针

\(update:\)本题使蒟蒻对指针恨之入骨,下次写数据结构如果用指针并不比结构体方便,蒟蒻可就要把指针束之高阁了!

\(Code:\)

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<tr1/unordered_map>
#define ls ch[0]
#define rs ch[1]
#define N 101005
using namespace std;
using namespace std :: tr1;
unordered_map<int,int>E[N];
int n,m,Q,opt,x,y;
int e[N][3];
int ans[N];
struct node
{
    int opt,u,v;
}que[N];
struct LCT
{
    LCT *ch[2],*f=NULL,*Mid,*lef,*rig;
    int s,w;
    bool rev;
    void clear()
    {
        ls=rs=Mid=lef=rig=NULL;
        s=w=0,rev=false;
    }
}rt,a[N],*q[N];
LCT *cnt,*g[N];
void connect(LCT *&x,LCT *&y,int son)
{
    if (!x)
    {
        y->ch[son]=NULL;
        return;
    }
    x->f=y;
    y->ch[son]=x;
}
bool isrt(LCT *&x)
{
    return x->f->ls!=x && x->f->rs!=x;
}
int id(LCT *&x)
{
    return (x->f->ls==x)?0:1;
}
void update(LCT *&x)
{
    x->s=x->w,x->Mid=x;
    if (x->ls && x->ls->s>x->s)
        x->s=x->ls->s,x->Mid=x->ls->Mid;
    if (x->rs && x->rs->s>x->s)
        x->s=x->rs->s,x->Mid=x->rs->Mid;
}
void rot(LCT *&x)
{
    LCT *y=x->f,*r=y->f;
    int yson=id(x),rson=id(y);
    if (isrt(y))
        x->f=r; else
        connect(x,r,rson);
    connect(x->ch[yson^1],y,yson);
    connect(y,x,yson^1);
    update(y),update(x);
}
void push_rev(LCT *&x)
{
    if (!x)
        return;
    swap(x->ls,x->rs);
    x->rev=!x->rev;
}
void push_down(LCT *&x)
{
    if (x->rev)
    {
        push_rev(x->ls),push_rev(x->rs);
        x->rev=false;
    }
}
void splay(LCT *&x)
{
    LCT *g=x;
    int k=0;
    q[++k]=g;
    while (!isrt(g))
    {
        g=g->f,q[++k]=g;
    }
    while (k)
        push_down(q[k--]);
    while (!isrt(x))
    {
        LCT *y=x->f;
        if (isrt(y))
            rot(x); else
        if (id(x)==id(y))
            rot(y),rot(x); else
            rot(x),rot(x);
    }
}
void access(LCT *x)
{
    for (LCT *y=NULL;x!=(&rt);y=x,x=x->f)
    {
        splay(x);
        x->rs=y;
        update(x);
    }
}
void makeroot(LCT *&x)
{
    access(x);
    splay(x);
    push_rev(x);
}
void split(LCT *&x,LCT *&y)
{
    makeroot(x);
    access(y);
    splay(y);
}
LCT* findroot(LCT *x)
{
    access(x),splay(x);
    push_down(x);
    while (x->ls)
    {
        x=x->ls;
        push_down(x);
    }
    return x;
}
void link(LCT *&x,LCT *&y)
{
    makeroot(x);
    x->f=y;
}
void cut(LCT *&x,LCT *&y)
{
    makeroot(x);
    access(y);
    splay(y);
    x->f=&rt,y->ls=NULL;
    update(y);
}
void link_MST(LCT *&x,LCT *&y,int z)
{
    if (findroot(x)!=findroot(y))
    {
        ++cnt;
        cnt->w=z,cnt->f=&rt;
        cnt->lef=x,cnt->rig=y;
        link(x,cnt);
        link(y,cnt);
    } else
    {
        split(x,y);
        if (y->s>z)
        {
            LCT *ct=y->Mid;
            cut(ct,ct->lef),cut(ct,ct->rig);
            ct->clear();
            ct->w=z,ct->f=&rt;
            ct->lef=x,ct->rig=y;
            link(ct,x);
            link(ct,y);
        }
    }
}
int main()
{
    scanf("%d%d%d",&n,&m,&Q);
    rt.w=-1;
    for (int i=1;i<=n;i++)
        g[i]=a+i,g[i]->w=0,g[i]->f=&rt;
    cnt=g[n];
    for (int i=1;i<=m;i++)
        scanf("%d%d%d",&e[i][0],&e[i][1],&e[i][2]),E[e[i][0]][e[i][1]]=E[e[i][1]][e[i][0]]=i;
    for (int i=1;i<=Q;i++)
    {
        scanf("%d%d%d",&que[i].opt,&que[i].u,&que[i].v);
        if (que[i].opt==2)
            E[que[i].u][que[i].v]=E[que[i].v][que[i].u]=-E[que[i].v][que[i].u];
    }
    for (int i=1;i<=m;i++)
        if (E[e[i][0]][e[i][1]]>0)
            link_MST(g[e[i][0]],g[e[i][1]],e[i][2]);
    for (int i=Q;i;i--)
    {
        int opt=que[i].opt,x=que[i].u,y=que[i].v;
        if (opt==1)
        {
            split(g[x],g[y]);
            ans[++ans[0]]=g[y]->s;
        } else
            link_MST(g[x],g[y],e[-E[x][y]][2]);
    }
    for (int i=ans[0];i;i--)
        printf("%d\n",ans[i]);
    return 0;
}

观察这部分代码(在函数\(link\_MST\)

if (y->s>z)
        {
            LCT *ct=y->Mid;
            cut(ct,ct->lef),cut(ct,ct->rig);
            ct->clear();
            ct->w=z,ct->f=&rt;
            ct->lef=x,ct->rig=y;
            link(ct,x);
            link(ct,y);
        }

由于我们建的特殊点度数为\(2\),那么我们将\(x,y\)这条链抽出来之后,一定包含所要断掉的特殊点两个相连的点,我们将该特殊点\(Splay\)到根,直接让它与左右儿子分离即可

所以\(cut\)可以去掉,两个相连的点也无需记录,改变为以下这部分代码

if (y->s>z)
        {
            LCT *ct=y->Mid;
            splay(ct);
            if (ct->ls)
                ct->ls->f=&rt;
            if (ct->rs)
                ct->rs->f=&rt;
            ct->clear();
            ct->w=z,ct->f=&rt;
            link(ct,x);
            link(ct,y);
        }
posted @ 2020-10-14 16:09  GK0328  阅读(82)  评论(0编辑  收藏  举报