当前位置: 代码迷 >> 综合 >> HDU多校第三场 1002 Blow up the city —— DAG支配树 + 容斥
  详细解决方案

HDU多校第三场 1002 Blow up the city —— DAG支配树 + 容斥

热度:69   发布时间:2024-01-09 10:52:13.0

题目链接:点我啊╭(╯^╰)╮

题目大意:

     n n n 个城市组成有向无环图,出度为 0 0 0 的城市为指挥城市
     q q q 次查询,每次给出两座重要城市
    问炸毁任意一个城市,使得从两座城市中的任意一座不能到达指挥城市的方案数

解题思路:

    先反向建图,要炸毁的城市就是从若干起点到两座城市的必经点
    则直接建 D A G DAG DAG 支配树
    若干起点到一座城市的必经点就是这个点的深度
    两个城市的答案考虑容斥
    即两座城市的深度减去 L C A LCA LCA 的深度,注意源点的深度

核心:DAG支配树的特性

#include<bits/stdc++.h>
#define rint register int
#define deb(x) cerr<<#x<<" = "<<(x)<<'\n';
using namespace std;
typedef long long ll;
typedef pair <int,int> pii;
const ll mod = 1e9 + 7;
const int maxn = 1e5 + 10;
int T, n, m, q, cnt;
int tp[maxn], in[maxn];
int dep[maxn], f[maxn][25];
vector <int> t[maxn];
vector <int> v[maxn], fa[maxn];int lca(int x, int y){if(dep[x]<dep[y]) swap(x, y);for(int i=20; ~i; i--)if(dep[f[x][i]]>=dep[y])x = f[x][i];if(x == y) return x;for(int i=20; ~i; i--)if(f[x][i] ^ f[y][i])x=f[x][i], y=f[y][i];return f[x][0];
}void build(int x){int lcaf = fa[x][0];for(int i=1; i<fa[x].size(); i++)lcaf = lca(lcaf, fa[x][i]);t[lcaf].push_back(x);dep[x] = dep[lcaf] + 1;f[x][0] = lcaf;for(int i=1; i<=20; i++)f[x][i] = f[f[x][i-1]][i-1];
}void tp_sort(){queue <int> Q;for(int i=1; i<=n; i++)if(!in[i]){in[i]++;v[0].push_back(i);fa[i].push_back(0);}Q.push(0);while(!Q.empty()){int q = Q.front();Q.pop();tp[cnt++] = q;for(auto i : v[q]){in[i]--;if(!in[i]){Q.push(i);build(i);}}}
}void init(){cnt = 0;for(int i=0; i<maxn; i++){in[i] = dep[i] = 0;v[i].clear();fa[i].clear();t[i].clear();}
}int main() {scanf("%d", &T);while(T--){init();scanf("%d%d", &n, &m);for(int i=0, x, y; i<m; i++){scanf("%d%d", &y, &x);v[x].push_back(y);fa[y].push_back(x);in[y]++;}tp_sort();scanf("%d", &q);while(q--){int x, y, ans = 0;scanf("%d%d", &x, &y);int lcaf = lca(x, y);ans = dep[x] + dep[y] - dep[lcaf];printf("%d\n", ans);}}
}