HDU 5956 树上进行斜率优化DP + 记录操作并撤销

来源:互联网 发布:java常用api详解 编辑:程序博客网 时间:2024/06/04 18:35

题意:以前,在神秘的大陆,有一个青蛙王国,由最年长的青蛙——长者统治着。这个王国由N座城市组成,从东到西编号。第一座城市是首都,座落在最东边。每一个城市,连接者几个或者没有连接几个西边的城市,并且只连接了一个东边的城市。每天,都有一些大新闻发生在一些城市。长者想尽快地知道。所以,青蛙新闻工作者的工作就是,跑得比其他青蛙都快。当有巨大新闻发生在某座城市的时候,这座城市的新闻工作者将会携带信息,跑向首都。当到达另一个城市的时候,他可以继续跑,也可停下来让其他的新闻工作者传输信息。这些新闻工作者由于太年轻并且简单,不能有效的跑很长的距离。结果,他们需要 L2的时间来跑一条长度为L的路径。除此之外,传达信息需要P的时间,是为了检查传达信息是否有误,因为信息的误差会使长者极度的生气。现在你高兴的收到一个任务:计算从所有城市发送信息到首都的所需的最长的时间。我想问公然膜蛤真的好?

解题思路:可以将图看成一个由1点为根的树,每个点到根结点为路径是唯一的。设dp[u]为u点传输信息到根节点的所需时间。a[u]为u点到根节点的距离。很明显,dp[u] = min{dp[k]+(sum[u]−sum[k])2+P | k是u的祖先)。用斜率优化优化DP转移即可。但是不同的点路径不同,所以这里还需要记录在这个点对于斜率优化的队列操作了什么,回溯离开这个点的时候,需要撤销这些操作,操作每个点有一个栈记录即可。对于从根节点转移吃出来,可以考虑单独转移,也可设置dp[1]=-P。

代码如下:

#include <bits/stdc++.h>using namespace std;#define MP(x, y) make_pair(x, y)typedef long long LL;const int N = 1e5+5;struct fs{    LL fz, fm;    fs(){fz = 0, fm = 1;};    fs(LL fz2, LL fm2) : fz(fz2) , fm(fm2) {        if(fm < 0){            fz = -fz;            fm = -fm;        }    }    bool operator <(const fs &rhs) const{        return fz * rhs.fm < fm * rhs.fz;    }    bool operator <(const LL rhs) const{        return *this < fs(rhs, 1LL);    }};int p[N], cnt;struct edge{    int v, w, nxt;    edge(){}    edge(int v, int w, int nxt) : v(v), w(w), nxt(nxt) {}}E[N*2];void addedge(int u, int v, int w){    E[cnt].v = v, E[cnt].w = w, E[cnt].nxt = p[u], p[u] = cnt++;}void init(){    memset(p, -1, sizeof(p)); cnt = 0;}void getmax(LL &x, LL y){    if(y > x) x = y;}int head, tail;LL ans, que[N], dp[N], sum[N]; //sum维护前缀和LL P;LL sqr(LL x){    return x * x;}int getDP(int i, int j){    return dp[j] + P + sqr(sum[i] - sum[j]);}fs getxl(int j, int k){ //取斜率    return fs(dp[j] + sqr(sum[j]) - dp[k] - sqr(sum[k]), 2 * (sum[j] - sum[k]));}void dfs(int u, int fa, int len){    sum[u] = sum[fa] + len;    //0 pop_front 2 pop_back 3 push_back    stack <pair <int, int> > stk;    if(u != 1){        while(tail - head >= 2 && getxl(que[head], que[head+1]) < sum[u]) stk.push(MP(0, que[head++]));        dp[u] = getDP(u, que[head]);        //dp[u] = min(dp[u], sum[u] * sum[u]);        while(tail - head >= 2 && getxl(que[tail-1], u) < getxl(que[tail-2], que[tail-1])) stk.push(MP(2, que[--tail]));    }    que[tail++] = u;    stk.push(MP(3, u));    getmax(ans, dp[u]);    for(int i = p[u]; ~i; i = E[i].nxt){        int v = E[i].v, w = E[i].w;        if(v == fa) continue;        dfs(v, u, w);    }    while(!stk.empty()){        int op = stk.top().first;        int v = stk.top().second;        stk.pop();        if(op == 0) que[--head] = v;        else if(op == 2) que[tail++] = v;        else if(op == 3) tail--;        else head++;    }}int main(){    int T, n;    scanf("%d", &T);    while(T--){        scanf("%d%lld", &n, &P);        init();        memset(sum, 0, sizeof(sum));        for(int i = 1; i < n; i++){            int u, v, w;            scanf("%d%d%d", &u, &v, &w);            addedge(u, v, w);            addedge(v, u, w);        }        ans = -1;        head = tail = 0;        dp[1] = -P;        dfs(1, 0, 0);        printf("%lld\n", ans);    }    return 0;}
0 0
原创粉丝点击