hdu 5324 Boring Class

来源:互联网 发布:java多泛型 编辑:程序博客网 时间:2024/06/07 14:30

题目描述:

给出两个序列L[i], R[i],求出最长的子序列v[i]满足:
v(1) ≥ 1, v(m) ≤ n,v(i) < v(i + 1). (for i from 1 to m - 1)
L(v(i)) ≥ L(v(i + 1)), R(v(i)) ≤ R(v(i + 1))(for i from 1 to m - 1)
n~1e5;

题解:

转化成求同时两个的最长单调不降子序列.
对于一维的求法:我们认为是(i, li)的单调不降子序列. 如果按照li从小到大的顺序往里面放,那么对于心将要往里放的i,来说, dp[i] = 维护的树状数组的从1到i的最大值. 同样,我们也可以按照i的顺序往里放,然后找<=li的树状数组中的最大值.
对于本题,其实是三维(i,li, ri). 如果我们按照i的顺序往里面放数,那么我们要找到的就是放在树套树结构中同时小于等于li和ri的最大的dp值.这样树套树的方法就有了:如果是两个线段树,那么先进入到1~li的区间的线段树节点来查询.进入节点内部之后: 要以ri为键值,来综合查找出一个最大的dp值.之后把线段树的节点有效值pushUp. 插入的话: 单点插入,一共是nlogn的空间复杂度.
独立于树套平衡树,我们还有一种更巧妙的方法来解这道题目.
对于(i,li,ri),想cdq分治.分治有什么好处呢? 只需要思考左端对右端的贡献就好,这样就会减少一维i!!!!!! 然后我们按照li的大小顺序把一个一个数放进去,用树状数组维护小于等于ri的最大的dp值,来+1作为dp[i]的值更新到树状数组中. 注意其中能够更新的只有mid+1到r的i, l到mid的i是不能更新的,只能放进去. 并且mid+1到r的是不能放到树状数组里面的. 和归并操作一样.这样完了之后再递归处理右边.

重点:

(1)想明白和以为的单调不降子序列的关系.以及熟练掌握用树状数组求单调不降子序列的思想,放进去的顺序的思维很好.
(2)用树状数组的思想来求3维不降子序列,考虑到树套树.
(3)三维减少一维的方法是分治.想明白cdq分治的影响部分.

代码:

////cdq分治.需要注意的地方很多#include <cstdio>#include <algorithm>#include <cstring>using namespace std;int n;struct node {    int l, r, idx;    friend bool operator < (node x, node y) {        return x.l < y.l || (x.l == y.l && x.r < y.r) || (x.l == y.l && x.r == y.r && x.idx < y.idx);    }}p[50010];int hs[50010];struct ans_node {    int sum, idx;    ans_node(int _sum = 0, int _pre = 0) {        sum = _sum;        idx = _pre;    }    friend bool operator < (ans_node x, ans_node y) {        return x.sum < y.sum || x.sum == y.sum && x.idx > y.idx;    }}C[50010], f[50010];int ans, ans_pos, prepre[50010];ans_node getMax(int x) {    ans_node ret = ans_node(0, 0);    while (x > 0) {        ret = max(ret, C[x]);        x -= x & -x;    }    return ret;}bool cmp(node x, node y) {    return x.idx < y.idx;}void solve(int l, int r) {    //printf("@#$%d %din\n", l, r);    if (l == r) {        if (f[l].sum == 0) {            f[l].sum = 1;            f[l].idx= l;        }        //printf("@#$%d %dout\n", l, r);        return;    }    int mid = (l + r) >> 1;    solve(mid + 1, r);    int i = l, j = mid + 1;    sort(p + l, p + mid + 1);    sort(p + mid + 1, p + r + 1);    int hs_len = 0;    for (int i = mid + 1; i <= r; ++i) {        hs[hs_len++] = p[i].r;    }    sort(hs, hs + hs_len);    hs_len = unique(hs, hs + hs_len) - hs;    for (int i = 0; i <= hs_len; ++i) {        C[i] = 0;    }    for (int i = l; i <= mid; ++i) {        int pos;        while (j <= r && p[j].l <= p[i].l) {            pos = lower_bound(hs, hs + hs_len, p[j].r) - hs + 1;            while (pos <= hs_len) {                C[pos] = max(C[pos], f[p[j].idx]);                pos += pos & -pos;            }            j++;        }        pos = upper_bound(hs, hs + hs_len, p[i].r) - hs;        ans_node max_nxt = getMax(pos), max_now = ans_node(f[p[i].idx].sum, prepre[p[i].idx]);        max_nxt.sum++;        if (max_now < max_nxt) {//注意,不能直接更新,因为以前的数可能会已经产生了影响.            f[p[i].idx] = max_nxt;            prepre[p[i].idx] = f[p[i].idx].idx;            //printf("------%d %d\n", p[i].idx, f[p[i].idx].idx);            f[p[i].idx].idx = p[i].idx;        }    }    sort(p + l, p + mid + 1, cmp);    solve(l, mid);    //printf("@#$%d %dout\n", l, r);}int main() {    //freopen("1009.in", "r", stdin);    //freopen("out.txt", "w", stdout);    while (~scanf("%d", &n)) {        memset(f, 0, sizeof f);        memset(prepre, 0, sizeof prepre);        for (int i = 1; i <= n; ++i) {            scanf("%d", &p[i].l);        }        for (int i = 1; i <= n; ++i) {            scanf("%d", &p[i].r);            p[i].r = -p[i].r;            p[i].idx = i;        }        solve(1, n);        int ans = 0, ans_pos = 1000010;        for (int i = 1; i <= n; ++i) {            if (f[i].sum > ans || f[i].sum == ans && f[i].idx < ans_pos) {                ans = f[i].sum;                ans_pos = f[i].idx;            }        }        printf("%d\n", ans);        printf("%d", ans_pos);        for (int k = prepre[ans_pos]; k > 0; k = prepre[k]) {            printf(" %d", k);        }        printf("\n");    }    return 0;}///////////////树套平衡树.  还没学习= = 这是别人的代码.    #include <iostream>    #include <cstdio>    #include <cstdlib>    #include <cstring>    #include <algorithm>    using namespace std;    const int maxn = 50010;    struct Node{        Node *ch[2];        int r;        int v; //第二维        int len; //长度        int idx; //下标        int mlen; //结点和结点左孩子右孩子里最大长度        int midx; //结点和结点左孩子右孩子里最大长度对应的下标        Node() {}        Node(int v, int len, int idx):v(v),len(len),idx(idx),mlen(len),midx(idx) {ch[0] = ch[1] = NULL; r = rand();}        int cmp(int x) const {            if (x == v) return -1;            return x < v ? 0 : 1;        }        void maintain(){            mlen = len;            midx = idx;            if (ch[0] != NULL && (ch[0]->mlen > mlen || (ch[0]->mlen == mlen && ch[0]->midx < midx))){                mlen = ch[0]->mlen;                midx = ch[0]->midx;            }            if (ch[1] != NULL && (ch[1]->mlen > mlen || (ch[1]->mlen == mlen && ch[1]->midx < midx))){                mlen = ch[1]->mlen;                midx = ch[1]->midx;            }        }    };    bool findMax(Node* a, Node* b){        if (a->mlen < b->mlen || (a->mlen == b->mlen && a->midx > b->midx)){            *a = *b;            return true;        }        return false;    }    namespace Treap{        int cntnode;        Node node[maxn*10];        void init(){            cntnode = 0;        }        Node* newNode(int v, int len, int idx){            node[++cntnode] = Node(v, len, idx);            return &node[cntnode];        }        void rotate(Node* &o, int d){            Node* k = o->ch[d^1]; o->ch[d^1] = k->ch[d]; k->ch[d] = o;            o->maintain(); k->maintain(); o = k;        }        void insert(Node* &o, int v, int len, int idx){            if (o == NULL) o = newNode(v, len, idx);            else {                int d = o->cmp(v);                if (d != -1){                    insert(o->ch[d], v, len, idx);                    if (o->r < o->ch[d]->r) rotate(o, d^1);                }                else                {                    if (len >= o->len){                        o->len = len;                        o->idx = idx;                    }                }            }            o->maintain();        }        Node search(Node *o, int v){            if (o == NULL){                return Node(-1, 0, -1);            }            else{                Node re, tmp;                if (o->v == v) {                    re = Node(o->v, o->len, o->idx);                    if (o->ch[1]){                        findMax(&re, o->ch[1]);                    }                }                else if (o->v > v){                    re = Node(o->v, o->len, o->idx);                    if (o->ch[1]){                        findMax(&re, o->ch[1]);                    }                    if (o->ch[0]){                        tmp = search(o->ch[0], v);                        findMax(&re, &tmp);                    }                }                else{                    re = search(o->ch[1], v);                }                return re;            }        }    }    namespace BIT{        Node* fwt[maxn];        int N;        void init(int n){            N = n;            memset(fwt, 0, sizeof fwt);        }        void add(int v1, int v2, int len, int idx){            while(v1 < N){                Treap::insert(fwt[v1], v2, len, idx);                v1 += (-v1)&v1;            }        }        Node query(int v1, int v2){            Node re, tmp;            re = Node(-1, 0, -1);            while(v1 > 0){                tmp = Treap::search(fwt[v1], v2);                findMax(&re, &tmp);                v1 -= (-v1)&v1;            }            return re;        }    }    struct Pe{        int L,R;        int i;        bool operator < (const Pe& rhs)const{            return L < rhs.L;        }    };    bool cmp(Pe a, Pe b){        return a.i < b.i;    }    int solo[maxn];    Pe pe[maxn];int pre[maxn];    void print(Node& a){        int id = a.midx;        printf("%d\n", a.mlen);        while(1){            printf("%d", id+1);            if (pre[id] == -1){                break;            }            printf(" ");            id = pre[id];        }        printf("\n");    }    int main(){        int n;        while(scanf("%d", &n) != EOF){            for(int i=0;i<n;i++){                pe[i].i = i;                scanf("%d", &pe[i].L);            }            for(int i=0;i<n;i++){                scanf("%d", &pe[i].R);            }            sort(pe, pe+n);            int m = 0;            solo[0] = ++m;            for(int i=1;i<n;i++){                if (pe[i].L != pe[i-1].L){                    solo[i] = ++m;                }                else{                    solo[i] = solo[i-1];                }            }            for(int i=0;i<n;i++){                pe[i].L = solo[i];            }            sort(pe, pe+n, cmp);            BIT::init(m+1);            Treap::init();            Node ans = Node(-1, 0, -1), tmp;            for(int i=n-1;i>=0;i--){                tmp = BIT::query(pe[i].L, pe[i].R);                pre[i] = tmp.midx;                tmp.mlen = tmp.mlen + 1;                tmp.midx = i;                BIT::add(pe[i].L, pe[i].R, tmp.mlen, tmp.midx);                findMax(&ans, &tmp);            }            print(ans);        }        return 0;    }
0 0