【 bzoj 2286 】 : [Sdoi2011]消耗战 - 树形DP

来源:互联网 发布:思科网络技术学院邮箱 编辑:程序博客网 时间:2024/05/07 09:44

  这道题的思路感觉挺赞的……
  暴力的DP,f[i]表示切到i点的最小代价,显然有f[u]=min{vip[v]?inf:f[v],dis(u,v)}
  这其中中间有很多dp都是不必要的,因为如果一条链D下来,那么两个关键点之间更新的权值都是相邻两点的距离,可以省略掉。
  然后就可以用一个应该是挺经典的做法:用单调栈维护一条链。
  这样思路就很明显了,先按dfs序排序,然后用单调栈维护一条当前DP的链,每当加入一个新的关键点的时候就看看它是不是接在了链上,不然就一直往上跑也就是弹栈,直到接到了链上,在弹的过程中DP就可以了。
  感觉这个做法可以用在很多跟删除连接关键点的边有关的题目里面。
  

#include <bits/stdc++.h>using namespace std;#define rep(i,a,b) for(int i = a , _ = b ; i <= _ ; i ++)#define per(i,a,b) for(int i = a , _ = b ; i >= _ ; i --)#define fore(i,u)  for(int i = head[u] ; i ; i = nxt[i] )#define maxn 250007#define maxm 500007inline int rd() {    char c = getchar();    while (!isdigit(c)) c = getchar() ; int x = c - '0';    while (isdigit(c = getchar())) x = x * 10 + c - '0';    return x;}template<class T> inline void upmin(T&a , T b) { if (a > b) a = b ; }typedef long long ll;const ll inf = 1ll << 60 ;typedef int arr_int[maxn];typedef ll  arr_ll [maxn];typedef int adj[maxm];arr_int head , pos , dep , h , st , g;arr_ll  f;adj to , nxt , val ;int dis[maxn][19];int fa[maxn][19];int n , ett , dfs_clock , top;inline void ins(int u , int v , int w) {    to[++ ett] = v , val[ett] = w , nxt[ett] = head[u] , head[u] = ett;}void dfs(int u) {    pos[u] = ++ dfs_clock;    rep (i , 1 , 18) fa[u][i] = fa[fa[u][i - 1]][i - 1] , dis[u][i] = min(dis[fa[u][i - 1]][i - 1] , dis[u][i - 1]);    fore (i , u) {        int v = to[i] , w = val[i];        if (v == fa[u][0]) continue;        dep[v] = dep[u] + 1 , fa[v][0] = u , dis[v][0] = w;        dfs(v);    }}inline int lca(int u , int v) {    if (dep[u] < dep[v]) swap(u , v);    int d = dep[u] - dep[v];    rep (i , 0 , 18) if ((1 << i) & d) u = fa[u][i];    if (u == v) return u;    per (i , 18 , 0) if (fa[u][i] != fa[v][i]) u = fa[u][i] , v = fa[v][i];    return fa[u][0];}inline ll  Dis(int u , int v) {    if (dep[u] < dep[v]) swap(u , v);    int d = dep[u] - dep[v];    int ret = 0x7fffffff;    rep (i , 0 , 18) if ((1 << i) & d) upmin(ret , dis[u][i]) , u = fa[u][i];    if (u == v) return ret;    per (i , 18 , 0) if (fa[u][i] != fa[v][i]) upmin(ret , min(dis[u][i] , dis[v][i])) , u = fa[u][i] , v = fa[v][i];    upmin(ret , min(dis[u][0] , dis[v][0]));    return (ll) ret;}void input() {    n = rd();    rep (i , 2 , n) {        int u = rd() , v = rd() , w = rd();        ins(u , v , w) , ins(v , u , w);    }    dep[1] = 1 , dfs(1);}void work(int k) {    st[top = 1] = 1;    f[top] = g[top] = 0;    rep (i , 1 , k) {        int p = lca(st[top] , h[i]);        while (dep[st[top]] > dep[p]) {            if (dep[st[top - 1]] <= dep[p]) {                ll tmp = min(g[top] ? inf : f[top] , Dis(p , st[top]));                st[top --] = 0;                if (st[top] != p) {                    st[++ top] = p;                    f[top] = 0 , g[top] = 0;                }                f[top] += tmp;                break;            } else {                f[top - 1] += min(g[top] ? inf : f[top] , Dis(st[top - 1] , st[top]));                st[top --] = 0;            }        }        if (st[top] != h[i]) {            st[++ top] = h[i];            f[top] = 0;        }        g[top] = 1;    }    for (;top > 1; st[top --] = 0)        f[top - 1] += min(g[top] ? inf : f[top] , Dis(st[top - 1] , st[top]));    printf("%lld\n" , f[1]);}bool cmp(const int a , const int b) {    return pos[a] < pos[b];}void solve() {    rep (m , 1 , rd()) {        int k = rd();        rep (i , 1 , k) h[i] = rd();        sort(h + 1 , h + k + 1 , cmp);        work(k);    }}int main() {    #ifndef ONLINE_JUDGE        freopen("data.txt" , "r" , stdin);    #endif    input();    solve();    return 0;}
0 0
原创粉丝点击