• BZOJ4229选择——LCT+并查集+离线(LCT动态维护边双连通分量)


    题目描述

    现在,我想知道自己是否还有选择。
    给定n个点m条边的无向图以及顺序发生的q个事件。
    每个事件都属于下面两种之一:
    1、删除某一条图上仍存在的边
    2、询问是否存在两条边不相交的路径可以从点u出发到点v

    输入

    第一行三个整数n,m,q
    接下来m行,每行两个整数u,v,表示u和v之间有一条边
    接下来q行,每行一个大写字母o和2个整数u、v,依次表示按顺序发生的q个事件:
    当o为’Z’时,表示删除一条u和v之间的边
    当o为’P’时,表示询问是否存在两条边不相交的路径可以从点u出发到点v

    输出

    对于每组询问,如果存在,输出Yes,否则输出No

    样例输入

    7 8 7
    1 2
    1 3
    1 4
    2 3
    3 4
    3 7
    7 4
    5 6
    Z 1 4
    P 1 3
    P 2 4
    Z 1 3
    P 1 3
    Z 6 5
    P 5 6

    样例输出

    Yes
    Yes
    No
    No

    提示

    对于全部数据,max(n,m,q)<=100000
     
     
    只有删边没有加边,删边并不好做,我们将询问离线倒过来做,这样删边就变成了加边。
    之后题目就转化成了BZOJ4998
    #include<set>
    #include<map>
    #include<queue>
    #include<stack>
    #include<cmath>
    #include<vector>
    #include<bitset>
    #include<cstdio>
    #include<cstring>
    #include<iostream>
    #include<algorithm>
    #define pr pair<int,int>
    #define ll long long
    using namespace std;
    int g[100010];
    int fa[100010];
    int f[100010];
    int s[100010][2];
    int st[100010];
    int r[100010];
    int n,m,p;
    int opt;
    int x,y;
    set<pr>b;
    char ch[10];
    int ans[100010];
    struct miku
    {
        int opt;
        int x,y;
    }q[100010];
    struct Miku
    {
        int x,y;
    }a[100010];
    int find(int x)
    {
        if(fa[x]==x)
        {
            return x;
        }
        return fa[x]=find(fa[x]);
    }
    int judge(int x)
    {
        if(g[x]==x)
        {
            return x;
        }
        return g[x]=judge(g[x]);
    }
    int is_root(int rt)
    {
        return rt!=s[find(f[rt])][0]&&rt!=s[find(f[rt])][1];
    }
    int get(int rt)
    {
        return rt==s[find(f[rt])][1];
    }
    void pushdown(int rt)
    {
        if(r[rt])
        {
            swap(s[rt][0],s[rt][1]);
            r[s[rt][0]]^=1;
            r[s[rt][1]]^=1;
            r[rt]^=1;
        }
    }
    void rotate(int rt)
    {
        int fa=find(f[rt]);
        int anc=find(f[fa]);
        int k=get(rt);
        if(!is_root(fa))
        {
            s[anc][get(fa)]=rt;
        }
        s[fa][k]=s[rt][k^1];
        f[s[fa][k]]=fa;
        s[rt][k^1]=fa;
        f[fa]=rt;
        f[rt]=anc;
    }
    void splay(int rt)
    {
        int top=0;
        st[++top]=rt;
        for(int i=rt;!is_root(i);i=find(f[i]))
        {
            st[++top]=find(f[i]);
        }
        for(int i=top;i>=1;i--)
        {
            pushdown(st[i]);
        }
        for(int fa;!is_root(rt);rotate(rt))
        {
            if(!is_root(fa=find(f[rt])))
            {
                rotate(get(fa)==get(rt)?fa:rt);
            }
        }
    }
    void access(int rt)
    {
        for(int x=0;rt;x=rt,rt=find(f[rt]))
        {
            splay(rt);
            s[rt][1]=x;
        }
    }
    void reverse(int rt)
    {
        access(rt);
        splay(rt);
        r[rt]^=1;
    }
    void dfs(int x,int rt)
    {
        fa[x]=rt;
        if(s[x][0])
        {
            dfs(s[x][0],rt);
        }
        if(s[x][1])
        {
            dfs(s[x][1],rt);
        }
    }
    void link(int x,int y)
    {
        int fx=find(x);
        int fy=find(y);
        if(fx!=fy)
        {
            if(judge(fx)!=judge(fy))
            {
                reverse(fx);
                f[fx]=fy;
                g[g[fx]]=g[fy];
            }
            else
            {
                reverse(fx);
                access(fy);
                splay(fy);
                dfs(fy,fy);
                s[fy][0]=0;
            }
        }
    }
    int main()
    {
        scanf("%d%d%d",&n,&m,&p);
        for(int i=1;i<=n;i++)
        {
            fa[i]=g[i]=i;
        }
        for(int i=1;i<=m;i++)
        {
            scanf("%d%d",&a[i].x,&a[i].y);
        }
        for(int i=1;i<=p;i++)
        {
            scanf("%s",ch);
            scanf("%d%d",&q[i].x,&q[i].y);
            if(ch[0]=='Z')
            {
                q[i].opt=1;
                b.insert(make_pair(min(q[i].x,q[i].y),max(q[i].x,q[i].y)));
            }
        }
        for(int i=1;i<=m;i++)
        {
            if(b.find(make_pair(min(a[i].x,a[i].y),max(a[i].x,a[i].y)))==b.end())
            {
                link(a[i].x,a[i].y);
            }
        }
        for(int i=p;i>=1;i--)
        {
            if(q[i].opt)
            {
                link(q[i].x,q[i].y);
            }
            else
            {
                ans[i]=(find(q[i].x)==find(q[i].y));
            }
        }
        for(int i=1;i<=p;i++)
        {
            if(!q[i].opt)
            {
                printf(ans[i]?"Yes
    ":"No
    ");
            }
        }
    }
  • 相关阅读:
    vue插件编写与开发
    http状态码解读
    JavaScript 在HTML中的加载顺序
    vue props的理解
    vue项目中使用scss
    [LeetCode] 57. 插入区间
    [LeetCode] 55. 跳跃游戏
    [LeetCode] 56. 合并区间
    [LeetCode] 54. 螺旋矩阵
    [LeetCode] 53. 最大子序和
  • 原文地址:https://www.cnblogs.com/Khada-Jhin/p/9964556.html
Copyright © 2020-2023  润新知