zoj2319 线段树

题意:求二维都严格上升的最长上升自序列的长度 并输出任意解

解法:有经典的最长上升自序列问题采用最长上升子序列的解法 然后由此可以想到这个也同样可以这么写

首先将一维进行排序 然后我们对于第一维相同的要一起处理 除此之外 第一维度不同的则按照原来的方法写就可以了

那么我们需要延时插入 也就是说我们首先将一维相同的插入的最大值全部记录下来 然后再第一维度上升后再全部插入即可

#include<cstdio>
#include<vector>
#include<iostream>
#include<string.h>
#include<algorithm>
using namespace std;
#define maxn 111111
#define ls (rt<<1)
#define rs (rt<<1|1)
#define mid ((l+r)>>1)
int ma[maxn<<2];
inline void up(int rt){ma[rt]=max(ma[ls],ma[rs]);}
inline void build(int rt,int l,int r){
    ma[rt]=0;
    if(l==r)return ;
    build(ls,l,mid);
    build(rs,mid+1,r);
    up(rt);
}
inline void ins(int rt,int l,int r,int pos,int w){
    if(l==r){ma[rt]=max(ma[rt],w);return ;}
    if(pos<=mid)ins(ls,l,mid,pos,w);
    if(mid<pos)ins(rs,mid+1,r,pos,w);
    up(rt);
}
inline int query(int rt,int l,int r,int L,int R){
    if(L<=l&&r<=R)return ma[rt];
    int ans=0;
    if(L<=mid)ans=max(query(ls,l,mid,L,R),ans);
    if(mid<R)ans=max(query(rs,mid+1,r,L,R),ans);
    return ans;
}
struct node{
    int xi,yi,id;
}e[maxn];
int cmp(node x,node y){
    if(x.xi==y.xi)return x.yi<y.yi;
    return x.xi<y.xi;
}
struct node2{
    int pos,val;
};
int n,y[maxn];
vector<int>ans[maxn];
vector<node2>g;
int main(){
    int n,co,ma,maid,idx;
    while(~scanf("%d",&n)){
        co=0;
        ma=0;maid=-1;idx=-1;
        for(int i=0;i<n;++i){
            scanf("%d%d",&e[i].xi,&e[i].yi);
            y[co++]=e[i].yi;e[i].id=i+1;
            ans[i].clear();
        }
        ans[n].clear();
        sort(y,y+co);
        co=(int)(unique(y,y+co)-y);
        sort(e,e+n,cmp);
        build(1,1,co);
        g.clear();
        for(int i=0;i<n;++i){
            
            if(i!=0&&e[i].xi>e[i-1].xi){
                int sz=(int)g.size();
                for(int j=0;j<sz;++j){
                    node2 now=g[j];
                    ins(1,1,co,now.pos,now.val);
                }
                g.clear();
            }
            int cur=(int)(lower_bound(y,y+co,e[i].yi)-y),sum;
            if(cur==0){
                sum=1;
                ans[1].push_back(i);
            }
            else{
                sum=query(1,1,co,1,cur);
                sum+=1;
                ans[sum].push_back(i);
            }
            
            if(sum>ma){
                maid=e[i].id,ma=sum;idx=i;
            }
            
            node2 now;now.pos=cur+1,now.val=sum;
            g.push_back(now);
            
        }
        if(ma==1){
            printf("1\n%d\n",maid);
        }else{
            printf("%d\n%d",ma,maid);
            int xx=e[idx].xi,yy=e[idx].yi;
            int cc=1;
            while(cc<ma){
                
                int sz=(int)ans[ma-cc].size();
                for(int i=0;i<sz;++i){
                    if(e[ans[ma-cc][i]].xi<xx&&e[ans[ma-cc][i]].yi<yy){
                        xx=e[ans[ma-cc][i]].xi,yy=e[ans[ma-cc][i]].yi;
                        printf(" %d",e[ans[ma-cc][i]].id);
                        cc++;
                        break;
                    }
                }
            }
            printf("\n");
        }
    }
    return 0;
}
/*
 4
 1 5
 2 
 7
 3 6
 4 7
*/


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值