放一道比較基礎的LCA 的題目把 :CODEVS 2370 小機房的樹
阿新 • • 發佈:2017-10-27
desc esc clu n) out 。。 兩個 要求 printf
題目描述 Description
輸出描述 Output Description
小機房有棵煥狗種的樹,樹上有N個節點,節點標號為0到N-1,有兩只蟲子名叫飄狗和大吉狗,分居在兩個不同的節點上。有一天,他們想爬到一個節點上去搞基,但是作為兩只蟲子,他們不想花費太多精力。已知從某個節點爬到其父親節點要花費 c 的能量(從父親節點爬到此節點也相同),他們想找出一條花費精力最短的路,以使得搞基的時候精力旺盛,他們找到你要你設計一個程序來找到這條路,要求你告訴他們最少需要花費多少精力
輸入描述 Input Description第一行一個n,接下來n-1行每一行有三個整數u,v, c 。表示節點 u 爬到節點 v 需要花費 c 的精力。
第n+1行有一個整數m表示有m次詢問。接下來m行每一行有兩個整數 u ,v 表示兩只蟲子所在的節點
一共有m行,每一行一個整數,表示對於該次詢問所得出的最短距離。
樣例輸入 Sample Input3
1 0 1
2 0 1
3
1 0
2 0
1 2
樣例輸出 Sample Output1
1
2
數據範圍及提示 Data Size & Hint
1<=n<=50000, 1<=m<=75000, 0<=c<=1000
註意如何描述長度!
先來一發倍增的
#include<cstdio> #include<algorithm> #include<cmath> #definemaxn 1000500 #define ll long long using namespace std; struct st{ ll u,v,val,next; }s[maxn]; ll head[maxn],tot,n,m,u,v,val,ceng[maxn],ju[maxn],fa[maxn][20]; inline void add(ll u,ll v,ll val) { ++tot; s[tot].u = u; s[tot].v = v; s[tot].val = val; s[tot].next = head[u]; head[u]= tot; } inline void dfs(ll f,ll now) { fa[now][0] = f; ceng[now] = ceng[f] + 1; for(ll i=head[now];i;i=s[i].next) { v = s[i].v; if(v != f) { ju[v] = ju[now] + s[i].val;//沒錯!就是這裏!ju[i]存著點i到根節點的距離!!! dfs(now , v); } } } inline void doit() { for(ll j = 1;(1 << j) <= n;j++) for(ll i=1;i<=n;i++) fa[i][j] = fa[fa[i][j- 1]][j -1]; } inline ll lca(ll a,ll b) { if(ceng[a] > ceng[b]) swap(a,b); ll f = ceng[b] - ceng[a]; for(ll i = 0;(1 << i) <= n;i++) if((1 << i) & f) b = fa[b][i]; if(a != b) { for(ll i=(ll)log2(n);i>=0;i--) { if(fa[a][i] != fa[b][i]) { a = fa[a][i]; b = fa[b][i]; } } a = fa[a][0]; } return a; } int main(){ scanf("%lld",&n); for(ll i=1;i<n;i++) { scanf("%lld%lld%lld",&u,&v,&val); u++;//我不喜歡有0的情況,所以我就都加一了!!! v++; add(u,v,val); add(v,u,val); } dfs(0,1); doit(); scanf("%lld",&m); for(ll i=1;i<=m;i++) { scanf("%lld%lld",&u,&v); u++; v++; ll l = lca(u,v); printf("%lld\n",ju[u] + ju[v] - ju[l] * 2);//求出兩點之間距離(自己想想為什麽。。。) } }
放一道比較基礎的LCA 的題目把 :CODEVS 2370 小機房的樹