jzoj3960 [GDOI2015模拟12.21]鸡腿の出行 圆方树+lca

Description


【故事の背景】

鸡腿君,CZYZ著名DS,江苏延陵人,天朝64年夏赴张江公学,遇学霸,遂溃逃。后至申城地铁,奈何不识路线,幸而得路人甲好心指路,乃至于邯郸路。

【问题の描述】

上海又叫做申城,那里的地铁一直是很拥挤的。鸡腿从张江去邯郸本部的路上常常是挤得……瘦了一圈。但是呢今天因为没有学霸的碾压,鸡腿心情很好决定要出去玩。为了避免遇上残酷的拥挤的地铁线,鸡腿想要查找一些路线中的必经地点,请你来告诉他吧。
上海的地铁被描述为N个点M条边的一个无向图,每次鸡腿会告诉你他在第S条路上,想要到第T条路上(别问我为什么是路上……),你能告诉他有多少个途中的点是他必须要经过的吗?

对于20%的数据1 ≤ N ≤ 10^2,1 ≤ M ≤ 10^3,1 ≤ Q ≤ 10^3;
对于40%的数据 1 ≤ N ≤ 10^3,1 ≤ M ≤ 10^4,1 ≤ Q ≤ 10^3;
对于100%的数据 1 ≤ N ≤ 10^4,1 ≤ M ≤ 10^5,1 ≤ Q ≤ 10^4,0

Solution


本弱第一题圆方树,从第一次听说到写题已经过去一个多月了
大概做法就是tarjan求点双,对于点双连成菊花图,这样图上的问题就能变成树上的问题了
把边当成点建图那么圆方树上两点间圆点数量即为答案

Code


#include <stdio.h>
#include <string.h>
#include <algorithm>
#include <stack>
#define rep(i,st,ed) for (register int i=st;i<=ed;++i)
#define drp(i,st,ed) for (register int i=st;i>=ed;--i)

const int N=300005;
const int E=800005;

struct edge {int y,next;} e[E];

std:: stack <int> stack;

int dfn[N],low[N],dep[N],sum[N],fa[N][21];
int ls[N],ls1[N],edCnt=1,tot,n,m;

bool vis[N];

int read() {
    int x=0,v=1; char ch=getchar();
    for (;ch<'0'||ch>'9';v=(ch=='-')?(-1):(v),ch=getchar());
    for (;ch<='9'&&ch>='0';x=x*10+ch-'0',ch=getchar());
    return x*v;
}

void add_edge(int x,int y) {
    e[++edCnt]=(edge) {y,ls[x]}; ls[x]=edCnt;
    e[++edCnt]=(edge) {x,ls[y]}; ls[y]=edCnt;
}

void add_edge1(int x,int y) {
    e[++edCnt]=(edge) {y,ls1[x]}; ls1[x]=edCnt;
    e[++edCnt]=(edge) {x,ls1[y]}; ls1[y]=edCnt;
}

void dfs1(int now,int from) {
    dfn[now]=low[now]=++dfn[0]; vis[now]=1;
    for (int i=ls[now];i;i=e[i].next) {
        if ((i^1)==from) continue;
        if (!dfn[e[i].y]) {
            stack.push(i); dfs1(e[i].y,i);
            low[now]=std:: min(low[now],low[e[i].y]);
            if (low[e[i].y]>=dfn[now]) {
                int y=0; ++ tot;
                while (y!=i) {
                    y=stack.top(); stack.pop();
                    add_edge1(tot,e[y].y);
                }
                add_edge1(now,tot);
            }
        } else if (vis[e[i].y]) low[now]=std:: min(low[now],dfn[e[i].y]);
    }
    vis[now]=1;
}

void dfs2(int now) {
    sum[now]+=(now<=n);
    rep(i,1,20) fa[now][i]=fa[fa[now][i-1]][i-1];
    for (int i=ls1[now];i;i=e[i].next) {
        if (e[i].y==fa[now][0]) continue;
        fa[e[i].y][0]=now; dep[e[i].y]=dep[now]+1;
        sum[e[i].y]+=sum[now];
        dfs2(e[i].y);
    }
}

int get_lca(int x,int y) {
    if (dep[x]<dep[y]) std:: swap(x,y);
    drp(i,20,0) if (dep[fa[x][i]]>=dep[y]) x=fa[x][i];
    if (x==y) return x;
    drp(i,20,0) if (fa[x][i]!=fa[y][i]) x=fa[x][i],y=fa[y][i];
    return fa[x][0];
}

int main(void) {
    n=read(),m=read();
    rep(i,1,m) {
        int x=read(),y=read();
        add_edge(x,i+n); add_edge(i+n,y);
    } tot=n+m; dep[1]=1;
    dfs1(1,-1);
    dfs2(1);
    for (int T=read();T--;) {
        int x=read()+n,y=read()+n;
        int lca=get_lca(x,y);
        printf("%d\n", sum[x]+sum[y]-2*sum[lca]+(lca<=n));
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/jpwang8/article/details/81045485