hdu 5324 Boring Class cdq分治+树状数组+离散化

来源:互联网 发布:二手车 知乎 编辑:程序博客网 时间:2024/05/21 07:48

题意:

给你两个序列,两个序列都有n个数。然后让你找到一个位置序列,对应到两个序列上,使得新的L序列非递增,R序列非递减。

问你最长的长度是多少,并输出字典序最小的方案。


思路:

人生的第一道cdq分治,一直觉得这些类型学会了放在比赛也做不出来就没去学了。。。但看到辣么多人会做。。。赶紧搞起。

思路、代码盗自别人blog:http://blog.csdn.net/u013007900/article/details/47111319


由于值太大,先把L、R序列的值都离散化。

首先定义dp[i]:以第i个数为开头的最长长度是多少。(已经定义出dp状态,如果n^2能过,直接dp就可搞了hhh。)

由于要求字典序最小,因此要从后面搞起。如果从前面搞起,dp[i]状态就应该定义为 以第i个数结尾的最长长度,就算让你找到最长长度,但很难得知字典序最小的那个。


大概过程:

先把序列一分为二,既然是从后面搞起,则先把右区间递归搞掉,搞完右区间,然后利用树状数组更新对左区间的影响,清空树状数组后再递归搞左区间。(由于L序列要求非递增,则利用树状数组来保存比当前Li小的Lj的dp最大值。)

最后,我相信不会cdq的还是不知道怎么写,去看代码吧,少年。


code:

#include <bits/stdc++.h>using namespace std;const int N = 5e4+5;typedef long long LL;struct PP {    int l, r;    int id;    bool operator < (const PP &cmp) const {        if(r != cmp.r) return r < cmp.r;        if(l != cmp.l) return l > cmp.l;    //nothing        return id < cmp.id;    }}a[N];PP p1[N], p2[N];int n, tn;int bit[N<<1];int ls[N<<1];int dp[N];void update(int x, int val) {    while(x <= tn) {        bit[x] = max(bit[x], val);        x += x&(-x);    }}int query(int x) {    int ret = 0;    while(x > 0) {        ret = max(ret, bit[x]);        x -= x&(-x);    }    return ret;}void clear(int x) {    while(x <= tn) {        bit[x] = 0;        x += x&(-x);    }}void cdq(int l, int r) {    if(l == r) {        int &d = dp[a[l].id];        d = max(d, 1);        return ;    }    int mid = (l+r)>>1;    cdq(mid+1, r);    for(int i = mid+1;i <= r; i++) p2[i] = a[i];    for(int i = l; i <= mid; i++) p1[i] = a[i];    sort(p1+l, p1+mid+1);    sort(p2+mid+1, p2+r+1);        for(int i = mid, j = r;i >= l; i--) {        while(j > mid && p2[j].r >= p1[i].r) {            update(p2[j].l, dp[p2[j].id]);            j--;        }        int &e = p1[i].id;        dp[e] = max(dp[e], query(p1[i].l)+1);    }    for(int i = mid+1;i <= r; i++) clear(p2[i].l);    cdq(l, mid);}void solve() {    memset(dp, 0, sizeof(dp));    memset(bit, 0, sizeof(bit));    cdq(1, n);    int maxv = -1;    for(int i = 1;i <= n; i++) maxv = max(maxv, dp[i]);    printf("%d\n", maxv);    bool flag = false;    int pre = 0;    for(int i = 1;i <= n; i++) {        if(dp[i] == maxv && (pre == 0||(a[pre].l>=a[i].l&&a[pre].r<=a[i].r))) {            if(!flag) {                flag = true;                printf("%d", i);            }            else printf(" %d", i);            maxv--;            pre = i;        }    }    puts("");}    int main() {    while(scanf("%d", &n) != EOF) {        for(int i = 1;i <= n; i++) scanf("%d", &a[i].l);        for(int i = 1;i <= n; i++) scanf("%d", &a[i].r);        for(int i = 1;i <= n; i++) a[i].id = i;        int cnt = 0;        for(int i = 1;i <= n; i++) {            ls[cnt++] = a[i].l;            ls[cnt++] = a[i].r;        }        sort(ls, ls+cnt);        cnt = unique(ls, ls+cnt)-ls;        tn = cnt;        for(int i = 1;i <= n; i++) {            a[i].l = lower_bound(ls, ls+cnt, a[i].l)-ls+1;            a[i].r = lower_bound(ls, ls+cnt, a[i].r)-ls+1;        }        solve();    }    return 0;}



0 0
原创粉丝点击