计蒜之道 青云的机房组网方案(中等)

来源:互联网 发布:矩阵乘法计算公式 编辑:程序博客网 时间:2024/04/30 22:47

用在线LCA进行预处理,在对给出的两个点i,j算距离时,只要求出它们的最近公共祖先即可.

#include <iostream>#include <cstdio>#include <algorithm>#include <cstring>#include <vector>#include <stack>#include <queue> #include <cmath>#define maxn 10005#define INF 1e9typedef long long ll;using namespace std;struct Edge{    Edge(int a, int b){        from = a;        to = b;    }    int from, to;};vector<Edge> edge;vector<int> v[maxn];int d[maxn<<1], vis[maxn], num[maxn];int dp[maxn<<1][55], kk[505][505];int len;void dfs(int j, int f, int h){    vis[j] = len;    d[len++] = h;    for(int i = 0; i < v[j].size(); i++){        Edge &e = edge[v[j][i]];        if(e.to != f){            dfs(e.to, e.from, h+1);            d[len++] = h;        }     } }void ST(){    for(int i = 0; i < len; i++)     dp[i][0] = d[i];    for(int j = 1; (1<<j) <= len; j++)       for(int i = 0; i+(1<<j) <= len; i++){        int a = dp[i][j-1], b = dp[i+(1<<(j-1))][j-1];        dp[i][j] = a < b ? a : b;    }}int gcd(int i, int j){    return j ? gcd(j, i % j) : i;}void Init(){    for(int i = 1; i <= 500; i++)     for(int j = i; j <= 500; j++){        if(gcd(i, j) == 1)         kk[j][i] = kk[i][j] = 1;     }}int main(){//  freopen("in.txt", "r", stdin);     int n;    Init();    while(scanf("%d", &n) == 1){        int a, b;        for(int i = 1; i <= n; i++)         scanf("%d", num+i);        for(int i = 1; i <= n; i++)         v[i].clear();        edge.clear();        for(int i = 1; i < n; i++){            scanf("%d%d", &a, &b);            edge.push_back(Edge(a, b));            edge.push_back(Edge(b, a));            int k = edge.size();            v[a].push_back(k-2);            v[b].push_back(k-1);        }        len = 0;        dfs(1, -1, 0);        ST();           int cnt = 0;        for(int i = 1; i <= n; i++)         for(int j = i+1; j <= n; j++){            if(kk[num[i]][num[j]]){                int k1 = vis[i];                int k2 = vis[j];                if(k1 > k2)                 swap(k1, k2);                int k = 0;                while(1<<(k+1) <= k2-k1+1)                 k++;                int a = dp[k1][k], b = dp[k2-(1<<k)+1][k];                a = a < b ? a : b;                cnt += d[k1] + d[k2] - 2 * a;            }         }         printf("%d\n", cnt);    }    return 0;}
0 0