• The 19th Zhejiang University Programming Contest


    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 	extbf{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
    ", x)
    #define Prl(x) printf("%lld
    ",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;
    }
  • 相关阅读:
    Repeater嵌套Repeater的结构
    解决还原数据库 出现单用户
    常见的一些C#开源框架或者开源项目
    vue 实现动态路由
    c#使用Split分割换行符
    SQL Server 时间戳与时间格式互相转换
    值与枚举的转化
    编程之美,让美国人科技高速发展,浅谈C语言带给美国的变化
    SQL CE数据库搭建和操作
    C# 与API
  • 原文地址:https://www.cnblogs.com/Hugh-Locke/p/10707482.html
Copyright © 2020-2023  润新知