The 19th Zhejiang University Programming Contest - H

Princess Cjb is caught by Heltion again! Her knights Little Sub and Little Potato are going to Heltion Kingdom to rescue her.

Heltion Kingdom is composed of  islands, numbered from  to . There are  bridges in the kingdom, among which the -th bridge connects the -th island and the -th island. The knights can go through each bridge in both directions.

Landing separately on the -th and the -th island, the two knights start their journey heading to the -th island where the princess is imprisoned. However, as the knights are fat and the bridges are unstable, there will be a risk of breaking down the bridge and falling into the water if they go through one or more common bridges during their journey.

Thus, to successfully bring back the princess, two paths \textbf{with no common bridges} are needed: one starts from the -th island and leads to the -th island, while the other starts from the -th island and also leads to the -th island.

As the princess is caught very often, the knights will ask you for help  times. Each time, given their starting islands and their goal, you need to tell them whether it's possible to find two paths satisfying the constraints above.
题意

意识到首先可以进行缩点,图中所有的桥将整个图分成了数个联通快,联通块内的点之间一定有至少两条路可以相互到达。

用Tarjan求出所有的桥,缩点之后意识到整个图变成了一片森林(如果保证图联通就是一颗树),可以发现如果存在合理的路,终点所在的点一定在两个骑士的起点中间,类似 的情况,三角形是终点,当然三个点之间可以插入任意个点。

那问题就变成了判断一棵树上一个点是否在两个点中间的情况,意识到情况只有两种情况(u,v为起点,标三角形的为终点),利用lca的方式判断是否满足这两种情况即可,不满足即为NO

#include <map>
#include <set>
#include <ctime>
#include <cmath>
#include <queue>
#include <stack>
#include <vector>
#include <string>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <sstream>
#include <iostream>
#include <algorithm>
#include <functional>
using namespace std;
#define For(i, x, y) for(int i=x;i<=y;i++)  
#define _For(i, x, y) for(int i=x;i>=y;i--)
#define Mem(f, x) memset(f,x,sizeof(f))  
#define Sca(x) scanf("%d", &x)
#define Sca2(x,y) scanf("%d%d",&x,&y)
#define Sca3(x,y,z) scanf("%d%d%d",&x,&y,&z)
#define Scl(x) scanf("%lld",&x);  
#define Pri(x) printf("%d\n", x)
#define Prl(x) printf("%lld\n",x);  
#define CLR(u) for(int i=0;i<=N;i++)u[i].clear();
#define LL long long
#define ULL unsigned long long  
#define mp make_pair
#define PII pair<int,int>
#define PIL pair<int,long long>
#define PLL pair<long long,long long>
#define pb push_back
#define fi first
#define se second 
typedef vector<int> VI;
int read(){int x = 0,f = 1;char c = getchar();while (c<'0' || c>'9'){if (c == '-') f = -1;c = getchar();}
while (c >= '0'&&c <= '9'){x = x * 10 + c - '0';c = getchar();}return x*f;}
const double eps = 1e-9;
const int maxn = 2e5 + 10;
const int maxm = 4e5 + 10;
const int INF = 0x3f3f3f3f;
const int mod = 1e9 + 7; 
int N,M,K;
struct Edge{
    int to,next;
    bool cut;
}edge[maxm * 2];
int head[maxn],tot;
const int SP = 20;
int pa[maxn][SP],dep[maxn];
int scc[maxn];
vector<int>P[maxn];
int ind[maxn];
int low[maxn],dfn[maxn],Stack[maxn],Index,top;
bool Instack[maxn];
int fa[maxn],fa2[maxn];
void add(int u,int v){
    edge[tot].to = v;
    edge[tot].next = head[u];
    edge[tot].cut = 0;
    head[u] = tot++;
}
void Tarjan(int u,int pre){
    int v;
    low[u] = dfn[u] = ++Index;
    Stack[top++] = u;
    Instack[u] = true;
    int son = 0;
    int pre_cnt = 0;
    for(int i = head[u]; ~i; i = edge[i].next){
        int v = edge[i].to;
        if(v == pre && pre_cnt == 0){
            pre_cnt++;
            continue;
        }
        if(!dfn[v]){
            son++;
            Tarjan(v,u);
            if(low[u] > low[v]) low[u] = low[v];
            if(low[v] > dfn[u]){
                edge[i].cut = edge[i ^ 1].cut = true;
            }
        }else if(low[u] > dfn[v]){
            low[u] = dfn[v];
        }
    }
    Instack[u] = false;
    top--;
}
int find(int x){
    if(x == fa[x]) return x;
    return fa[x] = find(fa[x]);
}
int find2(int x){
    if(x == fa2[x]) return x;
    return fa2[x] = find2(fa2[x]);
}
void Union2(int a,int b){
    a = find2(a); b = find2(b);
    fa2[a] = b;
}
void Union(int a,int b){
    a = find(a) ; b = find(b);
    fa[a] = b;
}
bool vis[maxn];
void dfs(int u,int la){
    pa[u][0] = la; dep[u] = dep[la] + 1;
    for(int i = 1; i < SP; i ++) pa[u][i] = pa[pa[u][i - 1]][i - 1];
    for(int i = 0 ; i < P[u].size(); i ++){
        int v = P[u][i];
        if(v == la) continue;
        dfs(v,u);
    }
}
int lca(int u,int v){
    if(dep[u] < dep[v]) swap(u,v);
    int t = dep[u] - dep[v];
    for(int i = 0 ; i < SP; i ++) if(t & (1 << i)) u = pa[u][i];
    for(int i = SP - 1; i >= 0 ; i --){
        int uu = pa[u][i],vv = pa[v][i];
        if(uu != vv){
            u = uu; v = vv;
        }
    }
    return u == v?u:pa[u][0];
}
vector<PII>E;
int main(){
    int T; Sca(T);
    while(T--){
        N = read(),M = read(),K = read();
        E.clear();
        for(int i = 0; i <= N ; i ++){
            vis[i] = low[i] = dfn[i] = Instack[i] = 0;
            head[i] = -1;
            fa2[i] = fa[i] = i;
        }
        Index = top = tot = 0;
        for(int i = 1; i <= M ; i ++){
            int u = read(),v = read();
            add(u,v); add(v,u);
        }
        
        for(int i = 1; i <= N ; i ++) if(!dfn[i]) Tarjan(i,i);
        for(int i = 1; i <= N ; i ++){
            for(int j = head[i]; ~j ; j = edge[j].next){
                int v = edge[j].to;
                if(!edge[j].cut) Union(i,v);
                else E.pb(mp(i,v));
                Union2(i,v);
            }
        }
        int cnt = 0;
        for(int i = 1; i <= N ; i ++){
            if(fa[i] == i) scc[++cnt] = i;
        }
        for(int i = 0 ; i < E.size(); i ++){
            if(E[i].fi <= E[i].se) continue;
            int a = find(E[i].fi),b = find(E[i].se);
            if(a == b) continue;
            P[a].pb(b); P[b].pb(a);
        }
        for(int i = 1; i <= N ; i ++){
            int x = find2(scc[i]);
            if(!vis[x]){
                vis[x] = 1;
                dep[scc[i]] = 0;
                dfs(scc[i],0);
            }
        }
        for(int i = 1; i <= K; i ++){
            int w = read(),u = read(),v = read();
            int pw = find2(w),pu = find2(u),pv = find2(v);
            if(pw != pu || pw != pv){
                puts("No"); continue;
            }
            int fw = find(w),fu = find(u),fv = find(v);
            if(dep[fu] > dep[fv]) swap(fu,fv);
            if(fw == fv || fu == fw){
                puts("Yes");
                continue;
            }
            int l = lca(fu,fv);
            if(lca(fv,fw) == fw && lca(fw,fu) == fu){
                puts("Yes");
                continue;
            }
            if(lca(fw,l) == l && (lca(fv,fw) == fw || lca(fu,fw) == fw)){
                puts("Yes");
                continue;
            }
            puts("No");
        }
        for(int i = 1; i <= cnt ; i ++) P[scc[i]].clear();
    }
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/Hugh-Locke/p/10707482.html