1. 程式人生 > >[NOIP 2015] 運輸計劃

[NOIP 2015] 運輸計劃

tel amp 計劃 sum -- 差分 getc noip esp

[題目鏈接]

https://www.lydsy.com/JudgeOnline/problem.php?id=4326

[算法]

首先,此題的答案是具有單調性的,因此可以二分答案mid

檢驗答案時,我們判斷每條路徑的長度是否大於mid,若大於mid,則說明至少要將這條路徑上的一條邊變為“蟲洞”

因此,我們可以對所有長度大於mid的路徑做樹上差分,若一條邊差分後的值 = 大於mid的路徑總數,那麽判斷最長路徑 - 這條邊的長度 <= mid

時間復雜度 : O(N log LEN)( LEN為每條邊的長度之和 )

[代碼]

此份代碼在BZOJ上通過了所有測試點,但在UOJ上由於常數原因只能拿到95分 , 此題需要一些常數優化

#include<bits/stdc++.h>
using namespace std;
#define MAXN 300010
#define MAXLOG 18

struct edge
{
        int to,w,nxt;
} e[MAXN << 1];

int i,n,m,tot,l,r,mid,ans,cnt,maxlen,num;
int u[MAXN],v[MAXN],a[MAXN],b[MAXN],t[MAXN],head[MAXN],depth[MAXN],sum[MAXN],s[MAXN],len[MAXN],dis[MAXN];
int anc[MAXN][MAXLOG]; namespace IO { template <typename T> inline void read(T &x) { int f = 1; x = 0; char c = getchar(); for (; !isdigit(c); c = getchar()) { if (c == -) f = -f; } for (; isdigit(c); c = getchar()) x = (x << 3
) + (x << 1) + c - 0; x *= f; } template <typename T> inline void write(T x) { if (x < 0) { putchar(-); x = -x; } if (x > 9) write(x / 10); putchar(x % 10 + 0); } template <typename T> inline void writeln(T x) { write(x); puts(""); } } ; inline void addedge(int u,int v,int w) { tot++; e[tot] = (edge){v,w,head[u]}; head[u] = tot; } inline void dfs(int u) { int i,v,w; for (i = 1; i < MAXLOG; i++) { if (depth[u] < (1 << i)) break; anc[u][i] = anc[anc[u][i - 1]][i - 1]; } for (i = head[u]; i; i = e[i].nxt) { v = e[i].to; w = e[i].w; if (v != anc[u][0]) { len[v] = w; anc[v][0] = u; depth[v] = depth[u] + 1; sum[v] = sum[u] + w; dfs(v); } } } inline void calc(int u) { int i,v; for (i = head[u]; i; i = e[i].nxt) { v = e[i].to; if (v != anc[u][0]) { calc(v); s[u] += s[v]; } } if (s[u] == num && len[u] > maxlen) maxlen = len[u]; } inline int lca(int x,int y) { int i,t; if (depth[x] > depth[y]) swap(x,y); t = depth[y] - depth[x]; for (i = 0; i < MAXLOG; i++) { if (t & (1 << i)) y = anc[y][i]; } if (x == y) return x; for (i = MAXLOG - 1; i >= 0; i--) { if (anc[x][i] != anc[y][i]) { x = anc[x][i]; y = anc[y][i]; } } return anc[x][0]; } inline int dist(int x,int y) { return sum[x] + sum[y] - 2 * sum[lca(x,y)]; } inline bool check(int mid) { int i,j,p,q,w,mx = 0; num = 0; for (i = 1; i <= n; i++) s[i] = 0; for (i = 1; i <= m; i++) { if (dis[i] > mid) { mx = max(mx,dis[i]); num++; s[u[i]]++; s[v[i]]++; s[lca(u[i],v[i])] -= 2; } } if (cnt == 0) return true; maxlen = 0; calc(1); return mx - maxlen <= mid; } int main() { IO :: read(n); IO :: read(m); for (i = 1; i < n; i++) { IO :: read(a[i]); IO :: read(b[i]); IO :: read(t[i]); addedge(a[i],b[i],t[i]); addedge(b[i],a[i],t[i]); cnt += t[i]; } dfs(1); for (i = 1; i <= m; i++) { IO :: read(u[i]); IO :: read(v[i]); dis[i] = dist(u[i],v[i]); } l = 0; r = cnt; while (l <= r) { mid = (l + r) >> 1; if (check(mid)) { r = mid - 1; ans = mid; } else l = mid + 1; } IO :: writeln(ans); return 0; }

[NOIP 2015] 運輸計劃