1. 程式人生 > >The North American Invitational Programming Contest 2016 I. Tourists(LCA)

The North American Invitational Programming Contest 2016 I. Tourists(LCA)

題目連結

求樹上i,j兩點之間的距離,其中i是j的因子。

我們可以先求出LCA(i,j),然後套這個公式: dist[i,j]=(dis[i]+dis[j]2dis[LCA(i,j)]+1)dist[i,j] = (dis[i]+dis[j]-2*dis[LCA(i,j)]+1) dis[i]表示1到i的距離。 最後要減去n,以為i != j。

AC程式碼:

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const
int N = 5e5+233; int pre[N][30],deep[N],n; int vis[N]; vector<int > e[N]; void bfs(int x){ queue<int > que; que.push(x); vis[x] = 1; deep[x] = 1; while(!que.empty()){ x = que.front(); que.pop(); // printf("x:%d ", x); // printf("deep[%d]:%d\n",x,deep[x] ); int size = e[x].size()
; for(int i=0;i<size;++i){ int u = e[x][i]; if(!vis[u]){ vis[u] = 1; que.push(u); pre[u][0] = x; deep[u] = deep[x] + 1; } } } } void getpre(){ for(int j=1;(1<<j)<=n;j++){ for(int i=1;i<=n;i++){ if(pre[i][j-1] != -1) pre[i][j]=pre[
pre[i][j-1]][j-1]; } } } int lca(int a,int b) { int i,j; if(deep[a]<deep[b])swap(a,b); for(i=0;(1<<i)<=deep[a];i++); i--; for(j=i;j>=0;j--) if(deep[a]-(1<<j)>=deep[b]) a=pre[a][j]; if(a==b)return a; for(j=i;j>=0;j--) { if(pre[a][j]!=-1&&pre[a][j]!=pre[b][j]) { a=pre[a][j]; b=pre[b][j]; } } return pre[a][0]; } int main(){ scanf("%d", &n); int u, v; memset(pre, -1, sizeof pre); for(int i=1; i<n; ++i){ scanf("%d %d", &u,&v); e[u].push_back(v); e[v].push_back(u); } bfs(1); // for(int i=1; i<=n; ++i) printf("%d\n", deep[i]); getpre(); // for(int i=1; i<=n; ++i) printf("%d\n", pre[i][0]); ll ans = 0; for(int i=1; i<=n; ++i){ for(int j=i; j<=n; j+=i){ ans += (deep[i]+deep[j]-2*deep[lca(i,j)]+1); } } printf("%lld\n", ans-n); return 0; }