[2016-05-25][树分治]
树分治不写就不熟啊,要多练习
/*hint:注意树分治中的vis和solve(G)并非solve(v)*/ #include <algorithm> #include <iostream> #include <cstring> #include <cstdio> #define maxn 200010 using namespace std; int N, L, R; const int inf = 0x7fffffff / 3; struct Edge{int to, nxt, w, dis;}edge[maxn]; int h[maxn], cnt; void add(int u, int v, int w){ edge[++ cnt] = (Edge){v, h[u], w, 0}; h[u] = cnt; edge[++ cnt] = (Edge){u, h[v], w, 0}; h[v] = cnt; } namespace seg{ int t[maxn << 2], v[maxn << 2], TMP; #define lc id << 1 #define rc id << 1 | 1 void init(){memset(t, 0, sizeof t);} void update(int id, int l, int r, int p, int val){ if(l == r){//线段树底层写错了。 if(v[id] == TMP)t[id] = max(t[id], val); else v[id] = TMP, t[id] = val; return; } v[id] = TMP; int mid = l + r >> 1; if(p <= mid)update(lc, l, mid, p, val); else update(rc, mid + 1, r, p, val); t[id] = -inf; if(v[lc] == TMP)t[id] = max(t[id], t[lc]); if(v[rc] == TMP)t[id] = max(t[id], t[rc]); } int ask(int id, int l, int r, int L, int R){ if(v[id] != TMP)return -inf; if(l == L && r == R)return t[id]; int mid = l + r >> 1; if(R <= mid)return ask(lc, l, mid, L, R); if(L > mid) return ask(rc, mid+1, r, L, R); return max(ask(lc, l, mid, L, mid), ask(rc, mid + 1, r, mid + 1, R)); } } int size[maxn], Sum, Mx, G; bool vis[maxn]; int dp[maxn]; void getg(int u, int fa){ size[u] = 1; dp[u] = 0; for(int i = h[u]; i; i = edge[i].nxt){ int v = edge[i].to; if(vis[v] || v == fa)continue; getg(v, u); size[u] += size[v]; dp[u] = max(dp[u], size[v]); } dp[u] = max(dp[u], Sum - size[u]); if(dp[u] < dp[G])G = u; } int d[maxn], vi[maxn], tim, mxdep; void getdis(int u, int fa, int dis, int dep){ if(dep > mxdep)mxdep = dep; if(vi[dep] != tim)vi[dep] = tim, d[dep] = dis; else d[dep] = max(d[dep], dis); for(int i = h[u]; i; i = edge[i].nxt){ int v = edge[i].to; if(v == fa || vis[v])continue; getdis(v, u, dis + edge[i].dis, dep + 1); } } bool solve(int u){ vis[u] = true; seg::TMP ++; seg::update(1, 0, N, 0, 0); for(int i = h[u]; i; i = edge[i].nxt){ int v = edge[i].to; if(vis[v])continue; tim ++; mxdep = 0; getdis(v, u, edge[i].dis, 1); for(int j = 0; j <= mxdep; j ++){ int A = L - j, B = R - j; if(A < 0)A = 0; if(B < 0)continue; if(seg::ask(1, 0, N, A, B) + d[j] >= 0) return true; } for(int j = 1; j <= mxdep; j ++) seg::update(1, 0, N, j, d[j]); } for(int i = h[u]; i; i = edge[i].nxt){ int v = edge[i].to; if(vis[v])continue; Sum = size[v], G = 0, getg(v, u); if(solve(G))return true; } return false; } bool check(int mid){ for(int i = 1; i <= cnt; i ++) if(edge[i].w >= mid)edge[i].dis = 1; else edge[i].dis = -1; for(int i = 1; i <= N; i ++)vis[i] = 0; seg::init(); dp[0] = inf, Sum = N, G = 0, getg(1, 0); return solve(G); } int main(){ scanf("%d%d%d", &N, &L, &R); static int hs[maxn], c = 0; int u, v, w, mn = inf, mx = -inf; for(int i = 1; i < N; i ++){ scanf("%d%d%d", &u, &v, &w); add(u, v, w); mx = max(mx, w); mn = min(mn, w); hs[++ c] = w; } sort(hs + 1, hs + 1 + c); c = unique(hs + 1, hs + 1 + c) - hs - 1; int l = 1, r = c; while(l < r){ int mid = l + (r - l + 1) / 2; if(check(hs[mid]))l = mid; else r = mid - 1; } printf("%d\n", hs[l]); return 0; }
给时光以生命,而不是给生命以时光。