码迷,mamicode.com
首页 > 其他好文 > 详细

Luogu P4172 [WC2006]水管局长

时间:2020-06-07 16:32:40      阅读:45      评论:0      收藏:0      [点我收藏+]

标签:c++   最大   problem   ota   etc   long   maker   维护   max   

链接

Luogu P4172

题意

给定一个 \(n\) 个点 \(m\) 条边的图和 \(q\) 次操作,每次操作分为以下两种:

  • 1 u v:查询 \(u\)\(v\) 的一条路径使得边权最大的边的权值最小。

  • 2 u v:将边 \((u,v)\) 删去。

\(\texttt{Data Range:}1\leq u\leq 10^3,1\leq m,q\leq 10^5\)

题解

边权最大的边的权值最小,考虑用 \(\texttt{LCT}\) 维护原图的最小生成树。同时由于存在断边操作不好维护,所以考虑时间倒流。

首先先将所有没有被割去的边连起来,然后对于每一个割边操作,由于是时间倒流的,所以在原图上连边,找新的最小生成树。

将每条边拆成一个点来维护边权,询问的话答案就是 \(\texttt{LCT}\)\((u,v)\) 链上的最小值。

代码

#include<bits/stdc++.h>
using namespace std;
typedef int ll;
typedef long long int li;
const ll MAXN=2e5+51; 
struct Edge{
    ll from,to,dist;
    inline bool operator <(const Edge &rhs)const
    {
        return dist<rhs.dist;
    }
};
Edge ed[MAXN];
ll n,m,qcnt,from,to,cnt,xx;
ll dis[1051][1051],op[MAXN],x[MAXN],y[MAXN],g[1051][1051],ffa[MAXN];
ll res[MAXN],ex[MAXN];
inline ll read()
{
    register ll num=0,neg=1;
    register char ch=getchar();
    while(!isdigit(ch)&&ch!=‘-‘)
    {
        ch=getchar();
    }
    if(ch==‘-‘)
    {
        neg=-1;
        ch=getchar();
    }
    while(isdigit(ch))
    {
        num=(num<<3)+(num<<1)+(ch-‘0‘);
        ch=getchar();
    }
    return num*neg;
}
inline ll find(ll x)
{
    return x==ffa[x]?x:ffa[x]=find(ffa[x]);
}
namespace LCT{
    struct Node{
        ll fa,mx,val,rv,sz;
        ll ch[2];
    };
    struct LinkCutTree{
        Node nd[MAXN];
        ll st[MAXN];
        #define ls nd[x].ch[0]
        #define rs nd[x].ch[1]
        inline bool nroot(ll x)
        {
            return nd[nd[x].fa].ch[0]==x||nd[nd[x].fa].ch[1]==x;
        }
        inline ll get(ll x,ll y)
        {
            return nd[x].val>nd[y].val?x:y;
        }
        inline void update(ll x)
        {
            nd[x].mx=get(x,get(nd[ls].mx,nd[rs].mx));
        }
        inline void reverse(ll x)
        {
            swap(ls,rs),nd[x].rv^=1;
        }
        inline void spread(ll x)
        {
            if(nd[x].rv)
            {
                ls?reverse(ls):(void)(1),rs?reverse(rs):(void)(1);
                nd[x].rv=0;
            }
        }
        inline void rotate(ll x)
        {
            ll fa=nd[x].fa,gfa=nd[fa].fa;
            ll dir=nd[fa].ch[1]==x,son=nd[x].ch[!dir];
            if(nroot(fa))
            {
                nd[gfa].ch[nd[gfa].ch[1]==fa]=x;
            }
            nd[x].ch[!dir]=fa,nd[fa].ch[dir]=son;
            if(son)
            {
                nd[son].fa=fa;
            }
            nd[fa].fa=x,nd[x].fa=gfa,update(fa);
        }
        inline void splay(ll x)
        {
            ll fa=x,gfa,cur=0;
            st[++cur]=fa;
            while(nroot(fa))
            {
                st[++cur]=fa=nd[fa].fa;
            }
            while(cur)
            {
                spread(st[cur--]);
            }
            while(nroot(x))
            {
                fa=nd[x].fa,gfa=nd[fa].fa;
                if(nroot(fa))
                {
                    rotate((nd[fa].ch[0]==x)^(nd[gfa].ch[0]==fa)?x:fa);
                }
                rotate(x);
            }
            update(x);
        }
        inline void access(ll x)
        {
            for(register int i=0;x;x=nd[i=x].fa)
            {
                splay(x),rs=i,update(x);
            }
        }
        inline void makeRoot(ll x)
        {
            access(x),splay(x),reverse(x);
        }
        inline void link(ll edx,ll x,ll y)
        {
            makeRoot(x);
            nd[nd[ex[edx]=x].fa=edx].fa=y,nd[edx].val=dis[x][y],update(edx);
        }
        inline void cut(ll x)
        {
            access(ex[x]),splay(x);
            ls=rs=nd[ls].fa=nd[rs].fa=0;
        }
        #undef ls
        #undef rs
    };
}
LCT::LinkCutTree lct;
int main()
{
    n=read(),m=read(),qcnt=read();
    for(register int i=1;i<=m;i++)
    {
        from=ed[i].from=read(),to=ed[i].to=read();
        dis[from][to]=dis[to][from]=ed[i].dist=read();
    }    
    for(register int i=1;i<=qcnt;i++)
    {
        op[i]=read(),x[i]=read(),y[i]=read();
        if(op[i]==2)
        {
            g[x[i]][y[i]]=g[y[i]][x[i]]=1;
        }
    }
    for(register int i=0;i<=n;i++)
    {
        ffa[i]=i;
    }
    sort(ed+1,ed+m+1),cnt=n*2-1;
    for(register int i=1;cnt>n;i++)
    {
        from=ed[i].from,to=ed[i].to;
        if(!g[from][to]&&find(from)!=find(to))
        {
            lct.link(cnt--,from,to),ffa[ffa[from]]=ffa[to];
        }
    }
    cnt=0;
    for(register int i=qcnt;i;i--)
    {
        lct.makeRoot(from=x[i]),lct.access(to=y[i]),lct.splay(to);
        if(op[i]==1)
        {
            res[++cnt]=lct.nd[lct.nd[to].mx].val;
        }
        if(op[i]==2)
        {
            if(lct.nd[lct.nd[to].mx].val>dis[from][to])
            {
                lct.cut(xx=lct.nd[to].mx),lct.link(xx,from,to);
            }
        }
    }
    while(cnt)
    {
        printf("%d\n",res[cnt--]);
    }
}

Luogu P4172 [WC2006]水管局长

标签:c++   最大   problem   ota   etc   long   maker   维护   max   

原文地址:https://www.cnblogs.com/Karry5307/p/13060920.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!