ZOJ 4097 Rescue the Princess

15 篇文章 0 订阅
5 篇文章 0 订阅

题目链接: http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemId=5986

题意

n n n个点, m m m条边的图,询问 z , x , y z,x,y z,x,y,是否能找到 x x x z z z y y y z z z没有重复经过路的方案。

题解

边双联通,进行缩点,然后用LCA判断。

代码
#include<bits/stdc++.h>
#define N 300010
#define INF 0x3f3f3f3f
#define eps 1e-10
// #define pi 3.141592653589793
// #define P 1000000007
#define LL long long
#define pb push_back
#define fi first
#define se second
#define cl clear
#define si size
#define lb lower_bound
#define ub upper_bound
#define mem(x) memset(x,0,sizeof x)
#define sc(x) scanf("%d",&x)
#define scc(x,y) scanf("%d%d",&x,&y)
#define sccc(x,y,z) scanf("%d%d%d",&x,&y,&z)
using namespace std;
typedef pair<int,int> pi;
int n,m,dfs_time,cnt,top;
vector<int> a[N],b[N];
int dfn[N],low[N],col[N],d[N]; bool f[N<<1],v[N];
int Stack[N];
void Tarjan(int u, int fa) {
    dfn[u] = low[u] = ++dfs_time;
    Stack[top++] = u;
    int k = 0,v;
    for (auto v:a[u]) {
        if (v == fa && !k) {
            k ++;
            continue;
        }
        if (!low[v]) {
            Tarjan(v, u);
            low[u] = min(low[u], low[v]);
        } else low[u] = min(low[u], dfn[v]);
    }
    if (dfn[u] == low[u]) {
        cnt++;
        do {
            v = Stack[--top];
            d[v] = cnt;
        } while (u != v);
    }
}

int L[N],fa[N],anc[23][N],rt[N],tt;

void lable(int x,int ffa,int p){
	rt[x]=tt;
    for (auto i:b[x]) if (i!=ffa) {
        fa[i]=x;
        L[i]=p+1;
        lable(i,x,p+1);
    }
}
void preprocess()
{
    for (int i=1;i<=cnt;i++) {
        anc[0][i]=fa[i];
        for (int j=1;(1<<j)<=cnt;j++) anc[j][i]=-1;
    }
    for (int j=1;(1<<j)<=cnt;j++)
        for (int i=1;i<=cnt;i++)
            if (anc[j-1][i]!=-1) anc[j][i]=anc[j-1][anc[j-1][i]];
}
int query(int p,int q)
{
    int log;
    if (L[p]<L[q]) swap(p,q);
    for (log=1;(1<<log)<=L[p];log++); log--;

    for (int i=log;i>=0;i--)
        if (L[p]-(1<<i)>=L[q])  p=anc[i][p];

    if (p==q)return p; //LCA为p
    for (int i=log;i>=0;i--)
        if (anc[i][p]!=-1 && anc[i][p]!=anc[i][q])
        p=anc[i][p],q=anc[i][q];
    
    return fa[p];//LCA为fa[p]
}


int main()
{
	int T,q;
	sc(T);
	while(T--){
		sccc(n,m,q);
		for (int i=1;i<=n;i++){
			a[i].clear(); b[i].clear();
			dfn[i]=low[i]=col[i]=rt[i]=v[i]=0;
		}for (int i=1;i<=m;i++) f[i]=0;
		
		for (int x,y,i=1;i<=m;i++){
			scc(x,y);
			a[x].pb(y); a[y].pb(x);
		}

		cnt=0;
		for (int i=1;i<=n;i++) if (!dfn[i]){
			dfs_time=0;
			Tarjan(i,-1);
		}

		for (int i=1;i<=n;i++) for (auto j:a[i]) if (d[i]!=d[j])
				b[d[i]].pb(d[j]);

		tt=0;
		for (int i=1;i<=cnt;i++) if(!rt[i]){
			tt++;
			lable(i,-1,0);
			
		}

		preprocess();

		while(q--){
			int x,y,z;
			sccc(z,x,y);
			z=d[z];x=d[x];y=d[y];
			if (!(rt[z]==rt[x] && rt[z]==rt[y])){
				puts("No");continue;
			}
			if (z==x || z==y) puts("Yes");else
			if (x==y) puts("No");else{
				int t1=query(z,x),t2=query(z,y),f1,f2;
				f1=(t1!=z); f2=(t2!=z);
				if (f1!=f2) puts("Yes");else
				if (f1 && f2)puts("No");else
				if (query(x,y)==z) puts("Yes");else 
					puts("No");
			}
		}
	}
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值