BZOJ 4553 [Tjoi2016&Heoi2016]序列

分治+线段树

记l[i]表示i可能变成的最小值(包括a[i]),同理r[i]最大值。显然i能从j转移当且仅当 i < j ,a[i]<=l[j],r[i]<=a[j],三维偏序,果断分治啊。每一次分治,同样枚举一维,排序一维,剩下一维用线段树即可。

#include<cstdio>
#include<algorithm>
#define cmin(u,v) ((u)>(v)?(u)=(v):0)
#define cmax(u,v) ((u)<(v)?(u)=(v):0)
#define N 100005
using namespace std;
namespace runzhe2000
{
    int a[N], l[N], r[N], arr[N<<1], f[N], n, m;
    struct event
    {
        int x, y, type, v;
        bool operator < (const event &that) const {return x == that.x ? type < that.type : x < that.x;}
    }eve[N];
    struct seg{int v;} t[N*5];
    void build(int x, int l, int r)
    {
        t[x].v = 0; if(l == r)return; int mid = (l+r)>>1;
        build(x<<1,l,mid); build(x<<1|1,mid+1,r);
    }
    int query(int x, int l, int r, int ql, int qr)
    {
        if(ql <= l && r <= qr) return t[x].v; 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;
    }
    void modi(int x, int l, int r, int p, int v)
    {
        if(l == r) {cmax(t[x].v, v); return;} int mid = (l+r)>>1;
        p <= mid ? modi(x<<1,l,mid,p,v) : modi(x<<1|1,mid+1,r,p,v);
        t[x].v = max(t[x<<1].v, t[x<<1|1].v);
    }
    void dc(int L, int R)
    {
        if(L == R) {cmax(f[L], 1); return;}
        int mid = (L+R)>>1, evecnt = 0, arrcnt = 0;
        dc(mid+1, R);
        for(int i = L; i <= mid; i++) arr[++arrcnt] = a[i], arr[++arrcnt] = r[i];
        for(int i = mid+1; i <= R; i++) arr[++arrcnt] = l[i], arr[++arrcnt] = a[i];
        sort(arr+1, arr+1+arrcnt); arrcnt = unique(arr+1, arr+1+arrcnt) - arr - 1;
        #define low(u) (int)(lower_bound(arr+1, arr+1+arrcnt, u) - arr)
        for(int i = L; i <= mid; i++) eve[++evecnt] = (event){low(a[i]), low(r[i]), 0, i};
        for(int i = mid+1; i <= R; i++) eve[++evecnt] = (event){low(l[i]), low(a[i]), 1, f[i]};
        sort(eve+1, eve+1+evecnt); build(1,1,arrcnt);
        for(int i = evecnt; i; i--)
        {
            if(eve[i].type) modi(1,1,arrcnt, eve[i].y, eve[i].v);
            else f[eve[i].v] = max(f[eve[i].v], 1 + query(1,1,arrcnt, eve[i].y, arrcnt));
        }
        dc(L,mid);
    }
    void main()
    {
        scanf("%d%d",&n,&m);
        for(int i = 1; i <= n; i++)
        {
            scanf("%d",&a[i]);
            l[i] = r[i] = a[i];
        }
        for(int i = 1; i <= m; i++)
        {
            int x, y; scanf("%d%d",&x,&y);
            cmin(l[x], y), cmax(r[x], y);
        }
        dc(1,n); int ans = 1;
        for(int i = 1; i <= n; i++) cmax(ans, f[i]);
        printf("%d\n",ans);
    }
}
int main()
{
    runzhe2000::main();
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值