NOIP模拟赛 夕阳

题目描述

“我有个愿望,我希望在灿烂千阳时遇见你。”

这是个有n个点的世界,有m条无向边连接着这n个点,但是不保证点之间能够互相到达。

“这个世界的夕阳,只在奇数长的简单路径的尽头。”一个神如是说。

于是我想知道对于一个点对(x,y),x到y之间的所有简单路径中是否存在长度为奇数的路径,只有这样,我才能找到存在有夕阳的路。

输入

第一行两个数n和m表示点的个数和边的条数。

接下来m行,每行两个数x,y表示x和y之间存在一条无向边。

接下来一行一个整数q表示询问的个数。

下面q行每行两个整数x,y表示一组询问,问x到y的所有简单路径中是否存在有长度为奇数的路径

输出

对于每组询问x,y,如果x与y之间存在一条长度为奇数的简单路径那么输出Yes否则输出No

样例输入

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

样例输出

No
Yes
Yes
Yes
No
Yes
Yes
Yes

数据范围

对于50%的数据,1≤n,m,q≤500

对于100%的数据,,1≤n,q,m≤100000

保证没有自环与重边。

题解:

若对原图解出生成树森林,那么询问点对(x,y)见是否有简单路径长度为奇数,可以看作求点对(x,y)是否有边在奇环上。

于是问题转化为判断是否有边在奇环中,这里解图的强联通分量,对于一个强联通分量,若其中有边在奇环上,那么分量中的所有边都在某个奇环上。

为了在分量中找到在奇环上的边,对图作tarjan算法,若点对(x,y)的深度的奇偶性相同,那么x和y的路径上的边都在奇环中。

#include<math.h>
#include<stdio.h>
#include<string.h>
#define buf 100001
#define MAXBUF 1<<9
#define dmin(a,b) ((a)<(b)?(a):(b))
inline void swp(int &x,int &y){
    x^=y,
    y^=x,
    x^=y;
}
char B[MAXBUF],*S=B,*T=B;
inline char gt(){
    if(S==T){
        T=(S=B)+fread(B,1,MAXBUF,stdin);
        if(S==T)
            return 0;
    }
    return *S++;
}
inline void F(int &x){
    x=0;int c=gt(),f=1;
    for(;c<48||c>57;c=gt())
        if(!(c^45))
            f=-1;
    for(;c>47&&c<58;c=gt())
        x=(x<<1)+(x<<3)+c-48;
    x*=f;
}
struct Pointer{
    int to;
    Pointer *nxt;
}*fst[buf];
Pointer mem[buf<<1],*tot=mem;
inline void link(int a,int b){
    *++tot=(Pointer){b,fst[a]},fst[a]=tot;
    *++tot=(Pointer){a,fst[b]},fst[b]=tot;
}
bool odd[buf];
int bin[20],n,m,dfn[buf],dep[buf],fa[buf][20],tim,s[buf],top,pb[buf],timer,low[buf],scn[buf],scx;
void tarjan(int x){
    pb[++top]=x;
    dfn[x]=low[x]=++timer;
    for(int i=1;i<=tim;i++)
        fa[x][i]=fa[fa[x][i-1]][i-1];
    for(Pointer *iter=fst[x];iter;iter=iter->nxt)
        if(iter->to^fa[x][0])
            if(!dfn[iter->to])
                fa[iter->to][0]=x,
                dep[iter->to]=dep[x]+1,
                tarjan(iter->to),
                low[x]=dmin(low[x],low[iter->to]);
            else
                if(!scn[iter->to]){
                    low[x]=dmin(low[x],dfn[iter->to]);
                    if(!((dep[iter->to]&1)^(dep[x]&1)))
                        odd[x]=1;
                }
    if(!(dfn[x]^low[x])){
        bool f=0;
        int v=top;
        for(;pb[v]^x;)
            f|=odd[pb[v--]];
        if(f)
            for(v++;v<=top;v++)
                s[pb[v]]++;
        ++scx;
        do
            v=pb[top--],
            scn[v]=scx;
        while(v^x);
    }
}
void dfs(int x){
    for(Pointer *iter=fst[x];iter;iter=iter->nxt)
        if(!(fa[iter->to][0]^x))
            s[iter->to]+=s[x],
            dfs(iter->to);
}
int lca(int x,int y){
    if(dep[x]<dep[y])
        swp(x,y);
    for(int i=tim;i>=0;i--)
        if(dep[fa[x][i]]>=dep[y])
            x=fa[x][i];
    if(!(x^y))
        return x;
    for(int i=tim;i>=0;i--)
        if(fa[x][i]^fa[y][i])
            x=fa[x][i],
            y=fa[y][i];
    return fa[x][0];
}
int main(){
    freopen("sunset.in","r",stdin),
    freopen("sunset.out","w",stdout);
    F(n),F(m);
    tim=log(n)/log(2)+1;
    bin[0]=1;
    for(int i=1;i<=tim;i++)
        bin[i]=bin[i-1]<<1;
    for(int x,y;m;m--)
        F(x),
        F(y),
        link(x,y);
    for(int i=1;i<=n;i++)
        if(!dfn[i])
            dep[i]=1,
            fa[i][0]=i,
            tarjan(i);
    for(int i=1;i<=n;i++)
        if(!(fa[i][0]^i))
            dfs(i);
    int q,x,y,t;
    for(F(q);q;q--){
        F(x),F(y);
        if(fa[x][tim]^fa[y][tim])
            puts("No");
        else
            t=lca(x,y),
            puts(((dep[x]+dep[y]-(dep[t]<<1))&1
                ||s[x]+s[y]-(s[t]<<1)>0)?
                "Yes":
                "No");
    }
    fclose(stdin),
    fclose(stdout);
}
posted @ 2016-11-15 11:22  keshuqi  阅读(382)  评论(0编辑  收藏  举报