POJ 2796 Feel Good 单调栈或者笛卡尔树

来源:互联网 发布:我的世界编程猫 编辑:程序博客网 时间:2024/06/07 08:26

题目:

http://poj.org/problem?id=2796

题意:

给定一个长度为n的数组,一个区间的值为这个区间的中所有值的和与最小值的乘积,求区间的最大值,并输出区间的左右端点

思路:

明显的单调栈,笛卡尔树也可以做

#include <iostream>#include <cstdio>#include <cstring>#include <algorithm>using namespace std;typedef long long ll;const int N = 100000 + 10, INF = 0x3f3f3f3f;int a[N];ll sum[N];int top, stk[N];int l[N], r[N];int main(){    int n;    while(~ scanf("%d", &n))    {        for(int i = 1; i <= n; i++) scanf("%d", &a[i]), sum[i] = sum[i-1] + a[i];        top = 0;        for(int i = 1; i <= n; i++)        {            while(top > 0 && a[stk[top-1]] >= a[i]) top--;            l[i] = (top == 0) ? 1 : stk[top-1] + 1;            stk[top++] = i;        }        top = 0;        for(int i = n; i >= 1; i--)        {            while(top > 0 && a[stk[top-1]] >= a[i]) top--;            r[i] = (top == 0) ? n : stk[top-1] - 1;            stk[top++] = i;        }        ll ans = -1;        int tl, tr;        for(int i = 1; i <= n; i++)        {            ll tmp = (sum[r[i]] - sum[l[i]-1]) * a[i];            if(tmp > ans)            {                ans = tmp, tl = l[i], tr = r[i];            }        }        printf("%lld\n", ans);        printf("%d %d\n", tl, tr);    }    return 0;}

笛卡尔树:

#include <iostream>#include <cstdio>#include <cstring>#include <algorithm>using namespace std;typedef pair<int, int> pii;typedef long long ll;const int N = 100000 + 10, INF = 0x3f3f3f3f;struct node{    int val, pri, fat, id, son[2];    friend bool operator< (node a, node b)    {        return a.val < b.val;    }    void init(int _val, int _pri, int _fat, int _id)    {        val = _val, pri = _pri, fat = _fat, id = _id;        son[0] = son[1] = 0;    }}tr[N];int top, stk[N];int root;int a[N];ll sum[N];ll ans;int ansl, ansr;int cartesian_build(int n){    top = 0;    for(int i = 1; i <= n; i++)    {        int k = top;        while(k > 0 && tr[stk[k-1]].pri >= tr[i].pri) k--;        if(k != 0)        {            tr[stk[k-1]].son[1] = i;            tr[i].fat = stk[k-1];        }        if(k != top)        {            tr[i].son[0] = stk[k];            tr[stk[k]].fat = i;        }        stk[k++] = i;        top = k;    }    return stk[0];}int dfs(int x, int f){    if(! x) return 0;    int l = dfs(tr[x].son[0], 0);    int r = dfs(tr[x].son[1], 1);    if(l == 0) l = tr[x].id; //说明此节点管辖区间的左端点是自身    if(r == 0) r = tr[x].id; //同理    ll tmp = (sum[r] - sum[l-1]) * tr[x].pri;    if(tmp > ans) ans = tmp, ansl = l, ansr = r;    return f ? r : l; //判断返回右端点还是左端点}int main(){    int n;    while(~ scanf("%d", &n))    {        tr[0].init(0, 0, 0, 0);        for(int i = 1; i <= n; i++)        {            scanf("%d", &a[i]);            sum[i] = sum[i-1] + a[i];            tr[i].init(i, a[i], 0, i);        }        sort(tr + 1, tr + 1 + n);        root = cartesian_build(n);        ans = -1;        dfs(root, 1);        printf("%lld\n", ans);        printf("%d %d\n", ansl, ansr);    }    return 0;}
原创粉丝点击