zoukankan      html  css  js  c++  java
  • [Tjoi2016&Heoi2016] 序列 CDQ分治

    题意:

    佳媛姐姐过生日的时候,她的小伙伴从某宝上买了一个有趣的玩具送给他。玩具上有一个数列,数列中某些项的值可能会变化,但同一个时刻最多只有一个值发生变化。

    现在佳媛姐姐已经研究出了所有变化的可能性,她想请教你,能否选出一个子序列,使得在任意一种变化中,这个子序列都是不降的?请你告诉她这个子序列的最长长度即可。

    注意:每种变化最多只有一个值发生变化。

    在样例输入1中,所有的变化是

    1 2 3
    2 2 3
    1 3 3
    1 1 3
    1 2 4

    选择子序列为原序列,即在任意一种变化中均为不降子序列在样例输入2中,所有的变化是:

    3 3 3

    3 2 3

    选择子序列为第一个元素和第三个元素,或者第二个元素和第三个元素,均可满足要求。

    输入:

    输入的第一行有两个正整数n, m,分别表示序列的长度和变化的个数。

    接下来一行有n个数,表示这个数列原始的状态。

    接下来m行,每行有2个数x, y,表示数列的第x项可以变化成y这个值。

    1 ≤ x ≤ n

    输出:

    输出一个整数,表示对应的答案

    思路:

    看到最长不下降子序列首先想的是用树状数组优化(dp),但这道题相较于正常的(LIS)多了一个改变,实际上也就是多加了几个限制。

    对于第(i)位和第(j)位如果选择(j)接在(i)后面,原来只用考虑(i<j)以及(a_i<a_j),这题要满足变化其中一个值后仍成立,所以需要考虑的有:
    1、(i<j)
    2、(a_i<=Mi[j])
    3、(Mx[i]<=a_j)
    此时题目就变成了一个三维偏序问题,可以考虑用CDQ求解了。

    即在外面维护条件1,CDQ中根据条件2排序,用树状数组直接维护条件3

    但由于等号两边比较的东西不同,所以相较以前的写法,这里对于([l,mid])([mid+1,r])的排序方式是不一样的。也就是对于左边区间直接用值进行升序排列,右区间根据Mi升序排列。

    而树状数组中每次在Mx的位置上进行更新,查询时则根据val

    应该没什么细节,只要不字母打错之类的

    #include<bits/stdc++.h>
    #define M 100005
    #define lowbit(x) (x&-x)
    using namespace std;
    int n,m,ans[M];
    struct node {
    	int id,x,mx,mi;//最大可以变成的 和最小可以变成的值
    	void add(int y) {
    		mx=max(mx,y),mi=min(mi,y);
    	}
    } a[M],p[M];
    struct Tree {
    	int cnt[M];
    	void add(int x,int y) {
    		while(x<M)cnt[x]=max(cnt[x],y),x+=lowbit(x);
    	}
    	int Query(int x) {
    		int res=0;
    		while(x)res=max(res,cnt[x]),x-=lowbit(x);
    		return res;
    	}
    	void del(int x) {
    		while(x<M)cnt[x]=0,x+=lowbit(x);
    	}
    } T;
    bool cmp_x(node A,node B) {
    	if(A.x!=B.x)return A.x<B.x;
    	return A.mx<B.mx;
    }
    bool cmp_mi(node A,node B) {
    	if(A.mi!=B.mi)return A.mi<B.mi;
    	return A.x<B.x;
    }
    bool cmp_id(node A,node B){
    	return A.id<B.id;
    } 
    void CDQ(int l,int r) {
    	while(l>=r)return;
    	int mid=(l+r)>>1;
    	CDQ(l,mid);
    	sort(a+l,a+mid+1,cmp_x);
    	sort(a+mid+1,a+r+1,cmp_mi);
    	int j=l;
    	for(int i=mid+1; i<=r; i++) {
    		while(j<=mid&&a[j].x<=a[i].mi) {
    			T.add(a[j].mx,ans[a[j].id]);
    			j++;
    		}
    		int t=T.Query(a[i].x);
    		ans[a[i].id]=max(ans[a[i].id],t+1);
    	}
    	for(int i=l; i<j; i++)T.del(a[i].mx);//撤销
    //	sort(a+mid+1,a+r+1,cmp_id);
    	for(int i=mid+1; i<=r; i++)a[i]=p[i];//还原成id升序排列
    	CDQ(mid+1,r);
    }
    int main() {
    //	freopen("data.in","r",stdin);
    	scanf("%d%d",&n,&m);
    	for(int i=1; i<=n; i++)scanf("%d",&a[i].x),a[i].mi=a[i].mx=a[i].x,a[i].id=i,ans[i]=1;//因为不管怎么样序列最短都有1
    	for(int i=1; i<=m; i++) {
    		int x,y;
    		scanf("%d%d",&x,&y);
    		a[x].add(y);
    	}
    	for(int i=1; i<=n; i++)p[i]=a[i];
    	int Ans=0;
    	CDQ(1,n);
    	for(int i=1; i<=n; i++)Ans=max(Ans,ans[i]);
    	printf("%d
    ",Ans);
    	return 0;
    }
    
  • 相关阅读:
    Java类的三大特征
    java语句
    Python数据类型深入学习之数字
    Python基础学习篇章四
    Python基础学习篇章三
    Python基础学习篇章二
    python基础学习篇章一
    项目中调用天气预报接口
    CI框架传递数组到view层问题记录
    记录使用CI框架开发项目时遇到的问题
  • 原文地址:https://www.cnblogs.com/cly1231/p/10984479.html
Copyright © 2011-2022 走看看