• 【bzoj3173】最长上升子序列


    Portal --> bzoj3173

    Solution

      感觉自己需要智力康复qwq

      首先题目给的这个序列肯定是一个(1-n)的排列,并且插入的顺序是从小到大

      仔细思考一下会发现如果知道了最终的序列,问题就比较好解决了,这里提供一种用线段树的做法:

      如果知道了最终的序列,记数字(i)在该序列中的位置为(loc[i]),那么我们按照(i)从小到大的顺序,查询结尾在([1,loc[i]))的这段位置中的最长上升子序列的最大值(mx),并将(mx+1)作为以(loc[i])位置为结尾的答案,插入到线段树中(loc[i])对应的节点里,复杂度是(O(nlogn))

      然后现在的问题是怎么求最终的序列

      这个可以用平衡树来写,不过其实也可以用线段树来写

      考虑反过来确定每一个数在最终序列中的位置,因为是反过来考虑的,所以一开始的时候每一个位置都有一个数,然后我们根据读入的插入位置,按照(n-1)的顺序,找到当前这个数的位置,然后将它删掉(也就是对应的线段树节点的(sum-1)

    ​  具体一点就是比如当前考虑到第(i)个数,读入这个数应该要插入在(a[i])的位置后面,也就是应该在当前这个序列的第(a[i]+1)个位置,那么找到这个位置,然后把这个位置删掉,这样就可以得到还没有插入这个数之前的序列的位置集合了,这部分的复杂度也是(O(nlogn))

    ​  然后就十分愉快地做完啦

      

      代码大概长这个样子

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    using namespace std;
    const int MAXN=100010,SEG=MAXN*4;
    namespace Seg{/*{{{*/
    	int ch[SEG][2],sum[SEG],mx[SEG];
    	int n,tot;
    	void pushup(int x){
    		sum[x]=sum[ch[x][0]]+sum[ch[x][1]];
    		mx[x]=max(mx[ch[x][0]],mx[ch[x][1]]);
    	}
    	void _build(int x,int l,int r){
    		sum[x]=0; mx[x]=0;
    		if (l==r){sum[x]=0; return;}
    		int mid=l+r>>1;
    		ch[x][0]=++tot; _build(ch[x][0],l,mid);
    		ch[x][1]=++tot; _build(ch[x][1],mid+1,r);
    		pushup(x);
    	}
    	void build(int _n){n=_n; tot=1; _build(1,1,n);}
    	void _update(int x,int d,int lx,int rx,int delta){
    		if (lx==rx) {sum[x]+=delta;mx[x]+=delta;return;}
    		int mid=lx+rx>>1;
    		if (d<=mid) _update(ch[x][0],d,lx,mid,delta);
    		else _update(ch[x][1],d,mid+1,rx,delta);
    		pushup(x);
    	}
    	void update(int d,int delta){_update(1,d,1,n,delta);}
    	int _query_mx(int x,int l,int r,int lx,int rx){
    		if (l<=lx&&rx<=r) return mx[x];
    		int mid=lx+rx>>1,ret=0;
    		if (l<=mid) ret=max(ret,_query_mx(ch[x][0],l,r,lx,mid));
    		if (r>mid) ret=max(ret,_query_mx(ch[x][1],l,r,mid+1,rx));
    		return ret;
    	}
    	int query(int l,int r){return _query_mx(1,l,r,1,n);}
    	int _get_loc(int x,int lx,int rx,int k){
    		if (lx==rx) return lx;
    		int mid=lx+rx>>1;
    		if (sum[ch[x][0]]>=k) return _get_loc(ch[x][0],lx,mid,k);
    		else return _get_loc(ch[x][1],mid+1,rx,k-sum[ch[x][0]]);
    	}
    	int get_loc(int k){return _get_loc(1,1,n,k);}
    };/*}}}*/
    int loc[MAXN],a[MAXN],b[MAXN];
    int n,m,ans;
    
    int main(){
    #ifndef ONLINE_JUDGE
    	freopen("a.in","r",stdin);
    #endif
    	scanf("%d",&n);
    	for (int i=1;i<=n;++i) scanf("%d",b+i),++b[i];
    	Seg::build(n);
    	for (int i=1;i<=n;++i) Seg::update(i,1);
    	for (int i=n;i>=1;--i){
    		loc[i]=Seg::get_loc(b[i]);
    		Seg::update(loc[i],-1);
    	}
    	for (int i=1;i<=n;++i) a[loc[i]]=i;
    
    	Seg::build(n);
    	ans=0;	
    	int tmp;
    	for (int i=1;i<=n;++i){
    		if (loc[i]>1)
    			tmp=Seg::query(1,loc[i]-1);
    		else
    			tmp=0;
    		Seg::update(loc[i],tmp+1);
    		ans=max(ans,tmp+1);
    		printf("%d
    ",ans);
    	}
    }
    
  • 相关阅读:
    【HDU1724】Ellipse-自适应Simpson积分法
    【HDU1724】Ellipse-自适应Simpson积分法
    【51Nod1227】平均最小公倍数-杜教筛
    【51Nod1227】平均最小公倍数-杜教筛
    【HDU5628】Clarke and math-狄利克雷卷积+快速幂
    【HDU5628】Clarke and math-狄利克雷卷积+快速幂
    deleted
    deleted
    deleted
    deleted
  • 原文地址:https://www.cnblogs.com/yoyoball/p/9190688.html
Copyright © 2020-2023  润新知