• 2019 Multi-University Training Contest 3 B 支配树


    题目传送门

    题意:给出衣服有向无环图(DAG),,定义出度为0的点为中心城市,每次询问给出两个点,求破坏任意一个城市,使得这两个点至少有一个点无法到达中心城市,求方案数。

    思路:首先建立反向图,将城市到若干个终点看成从若干个起点出发到某个城市,再用一个源点连接那些度为0    的点,即可看成从源点出发到某个城市。要炸掉一个点使得无法到达某个城市,那么需要炸掉的是从源点到该城市的必经点,考虑建立支配树,根据定义可知支配树到根的链上结点个数就是必经点的个数。两个城市的容斥减去 LCA 到根上这条链即可。由于保证是 DAG ,因此直接按拓扑序建树即可,建完树利用结点的 depth 来求点到根的链长,注意最后答案要减去一开始添加的源点。

      DAG支配树求法:先求拓扑序,按照拓扑序处理(建树)。对于一个点,所有能到达它的点在支配树中的lca,就是它支配树中的父亲。由于能到达他的点拓扑序必定比他本身小,所以肯定已经在建好的支配树上了,必定能求出lca。

      现在还不会非DAG的支配树,学习博客为  https://wenku.baidu.com/view/b06471d019e8b8f67d1cb91b.html

    #include<bits/stdc++.h>
    #define pb(a) push_back(a)
    #define clr(a) memset(a, 0, sizeof(a))
    using namespace std;
    const int maxn = 1e5 + 5;
    vector<int >ve[maxn],rve[maxn];
    int n,m,T;
    int deg[maxn],dep[maxn],id[maxn],tot;
    int f[maxn][20];
    int rt=n+1;
    void bfs(){
        rt=n+1;
        queue<int >q;
        for(int i=1;i<=n;i++){
            if(!deg[i]){
                q.push(i);
                ve[i].pb(rt);
                rve[rt].pb(i);
            }
        }
        while(!q.empty()){
            int u=q.front();
            q.pop();
            id[++tot]=u;
            int si=rve[u].size();
            for(int i=0;i<si;i++){
                int v=rve[u][i];
                if((--deg[v])==0){
                    q.push(v);
                }
            }
        }
    }
    int LCA(int x,int y){
        if(dep[x]>dep[y])swap(x,y);
        for(int i=19;i>=0;i--){
            if(dep[y]>dep[x]&&dep[x]<=dep[f[y][i]])y=f[y][i];
        }
        for(int i=19;i>=0;i--){
            if(f[x][i]!=f[y][i])x=f[x][i],y=f[y][i];
        }
        return x==y?x:f[x][0];
    }
    int main(){
        cin>>T;
        while(T--){
            cin>>n>>m;
            for(int i=1;i<=n+1;i++){
                ve[i].clear(),rve[i].clear();
                deg[i]=dep[i]=0;
            }
            tot=0;
            for(int i=1;i<=m;i++){
                int u,v;
                scanf("%d%d",&u,&v);
                ve[u].pb(v);
                rve[v].pb(u);
                deg[u]++;
            }
            bfs();
            dep[rt]=1;
            for(int i=1;i<=n;i++){
                int fa=-1;
                int u=id[i];
                int si=ve[u].size();
                for(int j=0;j<si;j++){
                    int v=ve[u][j];
                    fa=(fa==-1)?v:LCA(fa,v);
                }
                dep[u]=dep[fa]+1;
                f[u][0]=fa;
                for(int j=1;j<=19;j++){
                    f[u][j]=f[f[u][j-1]][j-1];
                }
            }
            int q,u,v;
            cin>>q;
            while(q--){
                scanf("%d%d",&u,&v);
                int lca=LCA(u,v);
                printf("%d
    ",dep[u]+dep[v]-dep[lca]-1);
            }
        }
    }
  • 相关阅读:
    PHP IIS SPY
    Java 教程整理:基础、项目全都有
    14门Linux课程,打通你Linux的任督二脉!
    给缺少Python项目实战经验的人
    Spark 简介与安装部署
    仿OpenStack开发云计算管理软件”--熟悉开发环境
    如何利用《C++ Primer》学习C++?
    J2SE核心开发实战(二)——字符串与包装类
    J2SE核心开发实战(一)——认识J2SE
    pygame开发PC端微信打飞机游戏
  • 原文地址:https://www.cnblogs.com/mountaink/p/11310928.html
Copyright © 2020-2023  润新知