zoukankan      html  css  js  c++  java
  • [HNOI2019]校园旅行

    [HNOI2019]校园旅行 

    点和点之间关系密切。考虑刷表然后O(1)回答

    暴力:

    f[i][j]i到j是否有回文路径,暴力枚举出边。O(m^2)(每个边的对儿会恰好被枚举4次)

    优化:

    题目只要求“可行性”。考虑在不改变可行性情况下减少边数

    提出来所有两边标号相同的边

    对于1和0的连通块,如果连通块是二分图,只保留生成树即可(因为连通块内,a到b经过的边的奇偶性确定,至于可能路途遥远一些,但是可以让对称的那一半重复往返走一条边

    如果不是,那么a到b的奇偶性可以是奇数可以是偶数,随便连一个自环即可。

    提出来所有两边标号不同的边

    这个图显然是二分图

    对于这个二分图,保留一个生成树即可

    同理也可以在对称的位置来回走

    对于二分图:

    1.连通块染色

    2.带权并查集

    (自环连一个就好了,否则还是会TLE)

    // luogu-judger-enable-o2
    #include<bits/stdc++.h>
    #define reg register int
    #define il inline
    #define fi first
    #define se second
    #define mk(a,b) make_pair(a,b)
    #define numb (ch^'0')
    #define pii pair<int,int>
    using namespace std;
    typedef long long ll;
    template<class T>il void rd(T &x){
        char ch;x=0;bool fl=false;
        while(!isdigit(ch=getchar()))(ch=='-')&&(fl=true);
        for(x=numb;isdigit(ch=getchar());x=x*10+numb);
        (fl==true)&&(x=-x);
    }
    template<class T>il void output(T x){if(x/10)output(x/10);putchar(x%10+'0');}
    template<class T>il void ot(T x){if(x<0) putchar('-'),x=-x;output(x);putchar(' ');}
    template<class T>il void prt(T a[],int st,int nd){for(reg i=st;i<=nd;++i) ot(a[i]);putchar('
    ');}
    
    namespace Miracle{
    const int N=5005;
    const int M=500000+5;
    int n,m,q;
    struct node{
        int nxt,to;
    }e[2*M+2*N];
    int hd[N],cnt;
    char s[N];
    int co[N];
    void add(int x,int y){
        // if(x<y) cout<<" add "<<x<<" and "<<y<<endl;
        e[++cnt].nxt=hd[x];
        e[cnt].to=y;
        hd[x]=cnt;
    }
    int ex[M],ey[M];
    int gf[N];
    int fin(int x){
        return gf[x]==x?x:gf[x]=fin(gf[x]);
    }
    int fa[N];
    int papa(int x){
        return fa[x]==x?x:fa[x]=papa(fa[x]);
    }
    int c[N];
    int num,rt[N];
    int ji[N];
    void dfs(int x,int se){
        c[x]=se;
        for(reg i=hd[x];i;i=e[i].nxt){
            int y=e[i].to;
            if(co[y]!=co[x]) continue;
            if(c[y]){
                if(c[y]==c[x]){
                    ji[num]=1;
                }
            }else{
                dfs(y,3-se);
            }
        }
    }
    void build(){
        for(reg i=1;i<=n;++i){
            if(c[i]==0){
                ++num;rt[num]=i;
                dfs(i,2);
            }
        }
        memset(hd,0,sizeof hd);cnt=0;
        for(reg i=1;i<=m;++i){
            if(co[ex[i]]==co[ey[i]]){
                int k1=fin(ex[i]),k2=fin(ey[i]);
                if(k1!=k2){
                    gf[k1]=k2;
                    add(ex[i],ey[i]);
                    add(ey[i],ex[i]);
                }
            }else{
                int k1=papa(ex[i]),k2=papa(ey[i]);
                if(k1!=k2){
                    fa[k1]=k2;
                    add(ex[i],ey[i]);
                    add(ey[i],ex[i]);
                }
            }
        }
        for(reg i=1;i<=num;++i){
            if(ji[i]){
                add(rt[i],rt[i]);
            }
        }
    }
    bool f[N][N];
    queue<pii>qs;
    void bfs(){
        for(reg i=1;i<=n;++i){
            f[i][i]=1;qs.push(mk(i,i));
        }
        for(reg i=1;i<=m;++i){
            if(co[ex[i]]==co[ey[i]]){
                f[ex[i]][ey[i]]=1;
                f[ey[i]][ex[i]]=1;
                qs.push(mk(ex[i],ey[i]));
            }
        }
        while(!qs.empty()){
            pii now=qs.front();qs.pop();
            int x=now.fi,y=now.se;
            // cout<<" bfs "<<x<<" "<<y<<endl;
            for(reg i=hd[x];i;i=e[i].nxt){
                int t1=e[i].to;
                for(reg j=hd[y];j;j=e[j].nxt){
                    int t2=e[j].to;
                    if(co[t1]==co[t2]&&!f[t1][t2]){
                        f[t1][t2]=f[t2][t1]=1;
                        qs.push(mk(t1,t2));
                    }
                }
            }
        }
    }
    int main(){
        rd(n);rd(m);rd(q);
        scanf("%s",s+1);
        for(reg i=1;i<=n;++i) co[i]=s[i]-'0';
        int x,y;
        for(reg i=1;i<=m;++i){
            rd(x);rd(y);
            ex[i]=x;ey[i]=y;
            add(x,y);add(y,x);
        }
        for(reg i=1;i<=n;++i){
            gf[i]=i;fa[i]=i;
        }
        build();
        // cout<<" cnt "<<cnt<<endl;
        bfs();
        while(q--){
            rd(x);rd(y);
            puts(f[x][y]?"YES":"NO");
        }
        return 0;
    }
    
    }
    signed main(){
        Miracle::main();
        return 0;
    }
    
    /*
       Author: *Miracle*
    */
  • 相关阅读:
    使非标准 Win32 控件或自画控件也具有 Windows XP 的界面风格
    MapInfo格式到ArcInfo格式的转换
    DICOM医学图像文件格式
    香港身份证
    Cheap Tricks: Let's Talk About METADATA TypeLibs
    ASP中使用ADO访问数据源
    DirectX 9 编程 DirectX窗口
    3DES Source Code
    OLEDB Resource(Session) Pooling (在Ado开发中使用连接池)
    《仙剑奇侠传4》仙剑问答全答案
  • 原文地址:https://www.cnblogs.com/Miracevin/p/10805455.html
Copyright © 2011-2022 走看看