hdu 5324 Boring Class 2015多校联合训练赛3 分治,最长不降子序列,最小字典序

Boring Class

Time Limit: 6000/3000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others)
Total Submission(s): 354    Accepted Submission(s): 75


Problem Description
Mr. Zstu and Mr. Hdu are taking a boring class , Mr. Zstu comes up with a problem to kill time, Mr. Hdu thinks it’s too easy, he solved it very quickly, what about you guys?
Here is the problem:
Give you two sequences  L1,L2,...,Ln  and  R1,R2,...,Rn .
Your task is to find a longest subsequence  v1,v2,...vm  satisfies
v11 , vmn , vi<vi+1  .(for i from 1 to m - 1)
LviLvi+1 , RviRvi+1 (for i from 1 to m - 1)
If there are many longest subsequence satisfy the condition, output the sequence which has the smallest lexicographic order.


 

Input
There are several test cases, each test case begins with an integer n.
1n50000
Both of the following two lines contain n integers describe the two sequences.
1Li,Ri109
 

Output
For each test case ,output the an integer m indicates the length of the longest subsequence as described.
Output m integers in the next line.
 

Sample Input
  
  
5 5 4 3 2 1 6 7 8 9 10 2 1 2 3 4
 

Sample Output
  
  
5 1 2 3 4 5 1 1
 

Source

求最长不降子序列。满足 Li >= Li+1  and Ri <= Ri+1

题解说可以用分治和树套树写,我先用set写,发现set不能完成二维上的查询。然后用splay写,超时了。

树套树还不懂怎么做到的空间,这里只会n^2的空间的方法。


本文采用分治方法:

由于保证最小字典序,则从后往前做,把大小关系取反,求最长上升子序列。

如果求出最长上升子序列,那么从左到右。如果最长长度为ans,遇到第一个满足len = ans的点输出,然后ans--,记录上一次输出的点p,再遇到len = ans的点q,满足p.l >=q.l and p.r <= q.r 就输出q点位置,然后ans--以此类推。


分治求最长上升子序列的方法。

------------------------------点已经逆序排序了

遇到[L,R]区间,先处理左区间,

             LLLLLLRRRRRR

             然后将R的id值 取反,R只能从L中传递过去更新len值,

             用新数组保存这些点,按L从小到大排序(逆序,所以从小到大),如果L相同则id值大的排前面。

                         从左到右枚举:

                                             遇到id值 > 0的点p在线段树中p.r 中插入该点的len值(取最大的)

                                             遇到id值 < 0 的点p查询满足r>=q.r中len最大的值,+1即更新len[p.id]

             然后处理右区间

             这样做,R先从L转移了。如果R要从R中点转移,因为最后才处理右区间,所以也会计算到的。

ps:线段树懒标记,方便情况,r要离散化,不然线段树保存不了


 


#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<math.h>
using namespace std;
#define maxn 200007

int lz[maxn],lc[maxn],rc[maxn],val[maxn];
int treecnt = 0;

void build(int u,int l,int r){
    if(l == r) return ;
    lc[u] = treecnt++;
    rc[u] = treecnt++;
    int mid = (l+r)/2;
    build(lc[u],l,mid);
    build(rc[u],mid+1,r);
}
void push_down(int u){
    if(lz[u]){
        lz[u] = 0;
        if(rc[u] != 0)
            lz[rc[u]] = 1,val[rc[u]] = 0;
        if(lc[u] != 0)
            lz[lc[u]] = 1,val[lc[u]] = 0;
    }
}
void update(int u){
    val[u] = max(val[rc[u]],val[lc[u]]);
}
int query(int u,int l,int r,int pp){
    push_down(u);
    if(l >= pp) return val[u];
    int mid = (l+r)/2;
    if(pp >= mid+1)
        return query(rc[u],mid+1,r,pp);
    return max(query(lc[u],l,mid,pp),query(rc[u],mid+1,r,pp));
}
void add(int u,int l,int r,int pp,int num){
    if(l == r){
        if(lz[u]) val[pp] = 0;
        lz[u] = 0;
        val[u] = max(val[u],num);
        return ;
    }
    push_down(u);
    int mid = (l+r)/2;
    if(pp >= mid+1)
        add(rc[u],mid+1,r,pp,num);
    else add(lc[u],l,mid,pp,num);
    update(u);
}
struct Node{
    int l,r,id;
};
Node p[maxn];
Node q[maxn];
Node w[maxn];

int comp(Node a,Node b){
    return a.r < b.r;
}
int comp1(Node a,Node b){
    return a.id > b.id;
}
int comp3(Node a,Node b){
    if(a.l == b.l) return a.id > b.id;
    return a.l < b.l;
}
int len[maxn];
void fenzhi2(int l,int r){
    if(r < l) return ;
    sort(q+l,q+r+1,comp3);
    for(int i = l;i <= r; i++){
        int id = abs(q[i].id);
        if(q[i].id < 0){
            len[id] = max(len[id],1+query(1,1,50000,q[i].r));
        }
        else {
            add(1,1,50000,q[i].r,len[id]);
        }
    }
    lz[1] = 1;
    val[1] = 0;
}
void fenzhi(int l,int r){
    if(l == r)  {
        len[p[l].id] = max(len[p[l].id],1);
        return ;
    }
    int mid = (l+r)/2;
    fenzhi(l,mid);
    for(int i = l;i <= r; i++){
        q[i] = p[i];
        if(i > mid) q[i].id *= -1;
    }
    fenzhi2(l,r);
    fenzhi(mid+1,r);
}
int comp2(Node a,Node b){
    return a.id < b.id;
}

int main(){
    int n;
    //freopen("1009.in","r",stdin);
    //freopen("10091.out","w",stdout);
    while(scanf("%d",&n)!=EOF){
        for(int i = 0;i < n;i++){
            scanf("%d",&p[i].l);
            p[i].id = i+1;
        }
        for(int i = 0;i < n; i++){
            scanf("%d",&p[i].r);
        }
        sort(p,p+n,comp);
        int cnt = 1,r = p[0].r;
        for(int i = 0;i < n; i++){
            if(p[i].r == r) p[i].r = cnt;
            else {
                r = p[i].r;
                p[i].r = ++cnt;
            }
        }
        sort(p,p+n,comp1);

        memset(len,0,sizeof(len));
        memset(lz,0,sizeof(lz));
        memset(val,0,sizeof(val));
        memset(lc,0,sizeof(lc));
        memset(rc,0,sizeof(rc));
        treecnt = 2;
        build(1,1,50000);

        fenzhi(0,n-1);

        int ans =0;
        for(int i = 1;i <= n; i++){
            ans = max(ans,len[i]);
        }
        sort(p,p+n,comp2);
        Node x;
        int flag = 1,be=-1;
        printf("%d\n",ans);
        for(int i = 0;i < n; i++){
            if(ans == len[p[i].id]){
                if(be == -1 || (p[i].l <= p[be].l && p[i].r >= p[be].r)){
                    if(flag == 0) printf(" ");
                    printf("%d",p[i].id);
                    flag = 0;
                    ans--;
                    be = i;
                }
            }
        }
        printf("\n");
    }
    return 0;
}










  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

GDRetop

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值