LOJ 6032 「雅礼集训 2017 Day2」水箱

来源:互联网 发布:ipad的蜂窝移动数据 编辑:程序博客网 时间:2024/09/21 08:52

线段树合并+树状数组

把0设成-1,问题就变成求最大前缀和。

考虑一个DP,记f[i]表示i隔板隔住了水,i之前最多满足多少条件。转移的时候枚举j表示[j,i]能是一个以j,i为左右端点的装水区间。

这样的问题是每次从新的i扫到一个j都要合并一遍区间里的所有标记,也就是一个区间会被合并多次。然而能够证明,不同的装水区间不超过O(n)个,且它们之间不会有交(端点可能相同)。

因此先找出这些区间,线段树维护一个区间的所有条件,求最大前缀和,合并就是直接线段树合并,这样总O(nlogn)。

#include<cstdio>#include<vector>#include<cstring>#include<algorithm>#define N 200005#define lowbit(_i) (_i&-_i)#define mkp(_i,_j) make_pair(_i,_j)using namespace std;namespace runzhe2000{    const int INF = 1<<29;    vector<pair<int,int> > vec[N], val[N];    int n, m, h[N], sta[N], stacnt, incnt, arr[N], arrcnt, sum, mx, f[N], cnt0, rank[N];    struct inter    {        int l, r, ans; inter *fa;        bool operator < (const inter &that) const        {            return r == that.r ? l < that.l : r > that.r;        }    }in[N<<1];    bool cmp_len(int a, int b){return in[a].r-in[a].l+1 < in[b].r-in[b].l+1;}    struct BIT    {        int t[N*10];        int query(int x)         {            int r = 0;             for(; x; x -= lowbit(x))             {                in[r].l < in[t[x]].l ? r = t[x] : 0;             }            return r;        }        void modi(int x, int v)         {            for(; x < N; x += lowbit(x))             {                if(in[v].r < in[t[x]].r || (in[v].r == in[t[x]].r && in[t[x]].l < in[v].l))                    t[x] = v;            }        }    }T;    struct SEG    {        int t[N*10];        void build(int x, int l, int r)        {            if(l == r) {t[x] = h[l]; return;} int mid = (l+r)>>1;            build(x<<1,l,mid); build(x<<1|1,mid+1,r);            t[x] = max(t[x<<1], t[x<<1|1]);        }        int query(int x, int l, int r, int ql, int qr)        {            if(ql <= l && r <= qr) return t[x]; int mid = (l+r)>>1, ret = 0;            if(ql <= mid) ret = max(ret, query(x<<1,l,mid,ql,qr));            if(mid <  qr) ret = max(ret, query(x<<1|1,mid+1,r,ql,qr));            return ret;        }    }S;    struct seg    {        seg *ch[2];        int sum, mx;    }mem[N*20], *tot, *null, *root[N];    seg *newseg()    {        seg *x = ++tot; *x = *null;        return x;    }    void init()    {        null = tot = mem;        null->ch[0] = null->ch[1] = null;        null->sum = null->mx = 0;        for(int i = 0; i <= incnt; i++)             root[i] = newseg();    }    void pushup(seg *x)    {        x->sum = x->ch[0]->sum + x->ch[1]->sum;        x->mx = max(x->ch[0]->mx, x->ch[0]->sum + x->ch[1]->mx);    }    void insert(seg *x, int l, int r, int p, int v)    {        if(l == r){x->sum += v; x->mx = max(x->sum, 0); return;} int mid = (l+r)>>1;        if(p <= mid)        {            if(x->ch[0] == null) x->ch[0] = newseg();            insert(x->ch[0], l, mid, p, v);        }        else        {            if(x->ch[1] == null) x->ch[1] = newseg();            insert(x->ch[1], mid+1, r, p, v);        }        pushup(x);    }    seg *merge(seg *x, seg *y, int l, int r)    {        if(x == null) return y;        if(y == null) return x;        seg *p = newseg();         if(l == r)        {            p->sum = x->sum + y->sum;            p->mx = max(0, p->sum);            return p;        }        int mid = (l+r)>>1;        p->ch[0] = merge(x->ch[0], y->ch[0], l, mid);        p->ch[1] = merge(x->ch[1], y->ch[1], mid+1, r);        pushup(p);         return p;    }    int query_sum(seg *x, int l, int r, int ql, int qr)    {        if(ql <= l && r <= qr) return x->sum; int mid = (l+r)>>1, ret = 0;        if(ql <= mid) ret += query_sum(x->ch[0], l, mid, ql, qr);        if(mid <  qr) ret += query_sum(x->ch[1], mid+1, r, ql, qr);        return ret;    }    void query_mx(seg *x, int l, int r, int ql, int qr)    {        if(ql <= l && r <= qr) {mx = max(mx, sum + x->mx); sum += x->sum; return;}         int mid = (l+r)>>1;        if(ql <= mid) query_mx(x->ch[0], l, mid, ql, qr);        if(mid <  qr) query_mx(x->ch[1], mid+1, r, ql, qr);    }    void main()    {        int task; scanf("%d",&task);        for(; task--; )        {            scanf("%d%d",&n,&m);            for(int i = 1; i < n; i++)             {                scanf("%d",&h[i]);                arr[++arrcnt] = h[i];                for(; stacnt && h[sta[stacnt]] <= h[i]; )                {                    in[++incnt] = (inter){sta[stacnt], i, 0, 0};                    stacnt--;                }                in[++incnt] = (inter){sta[stacnt], i, 0, 0};                sta[++stacnt] = i;            }            for(; ~stacnt; stacnt--) in[++incnt] = (inter){sta[stacnt], n, 0, 0};            for(int i = 1, p, y, k; i <= m; i++)            {                scanf("%d%d%d",&p,&y,&k);                cnt0 += k == 0;                vec[p].push_back(mkp(y,k));                arr[++arrcnt] = y;            }            arr[++arrcnt] = h[0] = h[n] = INF;            arr[++arrcnt] = -1;            sort(arr+1, arr+1+arrcnt);            arrcnt = unique(arr+1, arr+1+arrcnt) - arr - 1;            for(int i = 1; i <= n; i++)                 for(int j = 0, jj = vec[i].size(); j < jj; j++)                     vec[i][j].first = lower_bound(arr+1, arr+1+arrcnt, vec[i][j].first) - arr;            for(int i = 0; i <= n; i++) h[i] = lower_bound(arr+1, arr+1+arrcnt, h[i]) - arr;            sort(in+1, in+1+incnt);            in[0].l = -INF; in[0].r = INF;            for(int i = 1; i <= incnt; i++)            {                in[i].fa = &in[T.query(in[i].l+1)];                T.modi(in[i].l+1, i);            }            for(int i = 1; i <= incnt; i++) rank[i] = i;             sort(rank+1, rank+1+incnt, cmp_len);            init();             S.build(1,0,n);            for(int ii = 1, i; ii <= incnt; ii++)            {                i = rank[ii];                int d, u = min(h[in[i].l], h[in[i].r]);                if(in[i].l + 1 == in[i].r)                {                    for(int j = 0, jj = vec[in[i].r].size(); j < jj; j++)                    {                        insert(root[i], 1, arrcnt, vec[in[i].r][j].first, vec[in[i].r][j].second == 1 ? 1 : -1);                    }                    d = 1;                }                else d = S.query(1,0,n,in[i].l+1, in[i].r-1);                sum = 1 < d ? query_sum(root[i], 1, arrcnt, 1, d-1) : 0;                mx = 0; query_mx(root[i], 1, arrcnt, d, u-1);                in[i].ans = mx;                val[in[i].r].push_back(mkp(in[i].l, mx));                if(in[i].fa != &in[0]) root[in[i].fa-in] = merge(root[in[i].fa-in], root[i], 1, arrcnt);            }            for(int i = 1; i <= n; i++)                for(int j = 0, jj = val[i].size(); j < jj; j++)                    f[i] = max(f[i], f[val[i][j].first] + val[i][j].second);            printf("%d\n",f[n]+cnt0);            stacnt = arrcnt = incnt = cnt0 = 0;            memset(f, 0, sizeof(f));            memset(T.t, 0, sizeof(T.t));            memset(S.t, 0, sizeof(S.t));            for(int i = 0; i <= n; i++) vec[i].clear(), val[i].clear();        }    }}int main(){    runzhe2000::main();}
阅读全文
0 0
原创粉丝点击