BZOJ 4540 [Hnoi2016]序列

来源:互联网 发布:linux 下载php源码 编辑:程序博客网 时间:2024/06/14 07:20

线段树+矩阵

我来发一篇博客证明我还活着

题目要求的区间所有子区间的最小值之和不太容易合并,因此直接上数据结构不好做。

考虑离线做法。把所有询问右端点排序。

从左到右扫描整个序列,扫描到i时维护所有1ji的区间[j,i]的答案。那每做完一个i只要抓出当前询问的区间查询即可。

如何随着i右移,动态地维护前缀所有区间的答案?新加一个i进来的时候,只会增加右端点在i的子区间。这些新区间的最小值要么是i1时候的最小值即不变,要么就是a[i]。开线段树搞一搞,注意到都是线性变换,矩阵维护即可。

然后大概卡了一个中午的常数吧。

#include<cstdio>#include<vector>#include<cstring>#define N 100005using namespace std;int read(){    int r = 0, p = 0; char c = getchar();    for(; c < '0' || c > '9'; c = getchar()) c == '-' ? p = 1 : 0;    for(; c >='0' && c <='9'; r = r*10+c-'0', c = getchar());    return p?-r:r;}namespace runzhe2000{    typedef long long ll;    const int INF =  1<<30;    int n, q, a[N], sta[N], stacnt, nocnt;    ll ans[N];    struct que{int id, l; que *next;}node[N], *last[N];    struct matrix    {        ll a[3][3];        matrix(){memset(a,0,sizeof(a));}        matrix operator * (matrix &that)        {            matrix r;            for(int i = 0; i < 3; i++)            {                ll *rai = r.a[i], *ai = a[i];                for(int j = 0; j < 3; j++)                    for(int k = 0; k < 3; k++)                         rai[j] += ai[k]*that.a[k][j];            }            return r;        }    }I, mat_v, mat_sum;    struct seg    {        matrix val, tag;        int need;    }t[N*4];    void pushdown(int x)    {        if(!t[x].need)return; t[x].need = 0;        seg *ls = &t[x<<1], *rs = &t[x<<1|1];        ls->val = ls->val * t[x].tag;        ls->tag = ls->tag * t[x].tag;        rs->val = rs->val * t[x].tag;        rs->tag = rs->tag * t[x].tag;        ls->need = rs->need = 1;        t[x].tag = I;    }    void pushup(int x)    {        ll *a0 = t[x].val.a[0], *a0l = t[x<<1].val.a[0], *a0r = t[x<<1|1].val.a[0];        for(int i = 0; i < 3; i++) a0[i] = a0l[i] + a0r[i];    }    void build(int x, int l, int r)    {        t[x].val.a[0][2] = r-l+1; t[x].tag = I; t[x].need = 0;        if(l == r) return; int mid = (l+r)>>1;        build(x<<1,l,mid); build(x<<1|1,mid+1,r);    }    void modi(int x, int l, int r, int ql, int qr, matrix &val)    {        if(ql <= l && r <= qr)        {            t[x].need = 1;            t[x].tag = t[x].tag * val;            t[x].val = t[x].val * val;            return;        }        pushdown(x);        int mid = (l+r)>>1;         if(ql <= mid) modi(x<<1,l,mid,ql,qr,val);        if(mid <  qr) modi(x<<1|1,mid+1,r,ql,qr,val);        pushup(x);    }    ll query(int x, int l, int r, int ql, int qr)    {        if(ql <= l && r <= qr) return t[x].val.a[0][0];         int mid = (l+r)>>1; ll ret = 0;        pushdown(x);        if(ql <= mid) ret += query(x<<1,l,mid,ql,qr);        if(mid <  qr) ret += query(x<<1|1,mid+1,r,ql,qr);        return ret;    }    void main()    {        n = read(), q = read();        for(int i = 1; i <= n; i++) a[i] = read();        for(int i = 0; i < 3; i++) I.a[i][i] = mat_sum.a[i][i] = 1;        mat_sum.a[1][0] = 1;        mat_v.a[0][0] = mat_v.a[2][2] = 1;        build(1,1,n);        for(int i = 1; i <= q; i++)        {            int l = read(), r = read();            node[++nocnt] = (que){i,l,last[r]};            last[r] = &node[nocnt];        }        a[0] = -INF;        for(int i = 1; i <= n; i++)        {            for(; a[sta[stacnt]] >= a[i]; stacnt--);            mat_v.a[2][1] = a[i];            modi(1,1,n,sta[stacnt]+1,i,mat_v);            modi(1,1,n,1,i,mat_sum);            sta[++stacnt] = i;            for(que *j = last[i]; j; j = j->next)            {                ans[j->id] = query(1,1,n,j->l,i);            }        }        for(int i = 1; i <= q; i++) printf("%lld\n",ans[i]);    }}int main(){    runzhe2000::main();}
原创粉丝点击