zoukankan      html  css  js  c++  java
  • Luogu P4172 [WC2006]水管局长

    题意

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

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

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

    ( exttt{Data Range:}1leq uleq 10^3,1leq m,qleq 10^5)

    题解

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

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

    这里涉及到割掉环上边权最大的边的操作,为了更好的处理这个操作,可以在 ( exttt{LCT}) 上维护一个 (mx_i) 表示以 (i) 为根的子树上点权最大的是哪个。

    注意到我们将原树上的边拆成了点,而原树上的点在 ( exttt{LCT}) 上的权值为 (0),所以这样做是正确的。

    代码

    #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
    ",res[cnt--]);
        }
    }
    
  • 相关阅读:
    Knockout.js之初印象
    GroupBy之后加ToList和不加ToList有什么区别吗?
    值类型前加ref和out的区别
    引用类型前需要加ref?
    KEPServerEX连接SQLServer数据库操作
    nginx发布网站常用指令
    ASP.NET Core 布局 _Layout.cshtml
    ASP.NET Core-------appsettings.json文件配置与加载
    ASP.NET Core 入门程序
    ASP.NET.Core网站centerOS上部署发布
  • 原文地址:https://www.cnblogs.com/Karry5307/p/13060920.html
Copyright © 2011-2022 走看看