CF 650D Round 345 Div1 D
2016-03-08 19:19
381 查看
大意是给一个数组,若干询问,每一次把一个数字改为另一个数字,问当前数组最长上升子序列,询问之间是独立的。
注意到:假设初始数组的LIS长度为len。如果某一个位置的数字属于所有LIS,那么即便这个位置的数字被更改,答案至少是len-1,也有可能会因为变化维持len不变(未必是因为变化介于原来LIS前一个数字和后一个数字之间)。如果某一个位置的数字不是属于所有的LIS(属于某一种或者不属于任何LIS),那么答案至少是len,但也有可能因为变化新答案为len+1。至此,处理出所有位置的数字是否属于所有LIS的情况后,所有询问有了保底的答案。对于这两种情况,可能会产生不保底的情况,则需要对每一个询问查询,左边小于新数字的最大dp值,与右边大于新数字的最大dp值,两者相加再加上1与保底答案取最大值。具体操作,可以按照询问的位置对询问排序,离线处理。
具体写法有两种,一种是树状数组对原有数组数字与询问新数字全部离散化处理,以及基于LIS O(nlog(n))二分解法的写法。判断一个数字是否属于某一个LIS,条件是f[i]+g[i]==len-1? 其中f[i]和g[i]分别是以a[i]为结尾从1到i的LIS长度以及以a[i]为开端从i到n的LIS长度。判断一个数字是否属于所有LIS,则扫描所有属于某一种LIS的数字,统计它们的f值或者g值出现次数,如果某一个f值只出现了1次,则说明拥有这个f值的数字被所有LIS经过。
View Code
注意到:假设初始数组的LIS长度为len。如果某一个位置的数字属于所有LIS,那么即便这个位置的数字被更改,答案至少是len-1,也有可能会因为变化维持len不变(未必是因为变化介于原来LIS前一个数字和后一个数字之间)。如果某一个位置的数字不是属于所有的LIS(属于某一种或者不属于任何LIS),那么答案至少是len,但也有可能因为变化新答案为len+1。至此,处理出所有位置的数字是否属于所有LIS的情况后,所有询问有了保底的答案。对于这两种情况,可能会产生不保底的情况,则需要对每一个询问查询,左边小于新数字的最大dp值,与右边大于新数字的最大dp值,两者相加再加上1与保底答案取最大值。具体操作,可以按照询问的位置对询问排序,离线处理。
具体写法有两种,一种是树状数组对原有数组数字与询问新数字全部离散化处理,以及基于LIS O(nlog(n))二分解法的写法。判断一个数字是否属于某一个LIS,条件是f[i]+g[i]==len-1? 其中f[i]和g[i]分别是以a[i]为结尾从1到i的LIS长度以及以a[i]为开端从i到n的LIS长度。判断一个数字是否属于所有LIS,则扫描所有属于某一种LIS的数字,统计它们的f值或者g值出现次数,如果某一个f值只出现了1次,则说明拥有这个f值的数字被所有LIS经过。
#include <iostream> #include <vector> #include <algorithm> #include <string> #include <string.h> #include <stdio.h> #include <math.h> #include <stdlib.h> #include <queue> #include <stack> #include <map> #include <set> using namespace std; const int N=1e6+12345; const int INF=0x3f3f3f3f; int a ; struct Query { int p,v; int id; int ans; int l,r; bool operator < (const Query &o) const { return p<o.p; } }query ; int dp ; int f ,g ; int cnt ; int lis(int n,int *f){ fill(dp,dp+n,INF); for (int i=0;i<n;i++) { int pos=lower_bound(dp,dp+n,a[i])-dp; dp[pos]=a[i]; f[i]=pos+1; } return lower_bound(dp,dp+n,INF)-dp; } bool flag ; int ret ; int main(){ int n,m; scanf("%d %d",&n,&m); for (int i=0;i<n;i++) { scanf("%d",a+i); } for (int i=0;i<m;i++) { int x,y; scanf("%d %d",&x,&y); query[i].p=x-1; query[i].v=y; query[i].id=i; } int len=lis(n,f); for (int i=0;i<n;i++) { a[i]=-a[i]; } reverse(a,a+n); lis(n,g); reverse(g,g+n); for (int i=0;i<n;i++) { a[i]=-a[i]; } reverse(a,a+n); memset(cnt,0,sizeof cnt); for (int i=0;i<n;i++) { if (f[i]+g[i]-1==len) { cnt[f[i]]++; } } for (int i=0;i<n;i++) { if (f[i]+g[i]-1==len&&cnt[f[i]]==1) { flag[i]=true; } } sort(query,query+m); for (int i=0;i<m;i++) { int p=query[i].p; if (flag[p]) query[i].ans=len-1; else query[i].ans=len; } int st=0; fill(dp,dp+n,INF); for (int i=0;i<m;i++) { int p=query[i].p; for (;st<p;st++) { int pos=lower_bound(dp,dp+n,a[st])-dp; dp[pos]=a[st]; } int pos=lower_bound(dp,dp+n,query[i].v)-dp; query[i].l=pos; } for (int i=0;i<n;i++) { a[i]=-a[i]; } st=n-1; fill(dp,dp+n,INF); for (int i=m-1;i>=0;i--) { int p=query[i].p; for (;st>p;st--) { int pos=lower_bound(dp,dp+n,a[st])-dp; dp[pos]=a[st]; } int pos=lower_bound(dp,dp+n,-query[i].v)-dp; query[i].r=pos; query[i].ans=max(query[i].ans,query[i].l+query[i].r+1); ret[query[i].id]=query[i].ans; } for (int i=0;i<m;i++) { printf("%d\n",ret[i]); } return 0; }
View Code
相关文章推荐
- 【Codeforces Round 339 (Div 2)A】【水题 暴力】 LinkCut Tree 输出[l,r]范围内所有的k的幂数
- Adapter系列之ArrayAdapter
- 设计模式系列(一): 引言
- mac下使用Xcode编译运行tinyhttpd
- <%%>与<scriptrunat=server>,<%=%>与<%#%>的区别
- POJ 1088 滑雪(记忆化dfs)
- 异常情况下Activity数据的保存和恢复
- 胡庆龙
- Android Bundle
- 作业2 个人项目-数组求和
- 就拿胖子说事
- 313. Super Ugly Number
- Redis应用场景
- ML2分层端口绑定技术在SDN开发中的应用(一)
- 通过JVM 参数 实现spring 应用的二进制代码与配置分离。
- 学期博客:学习进度条
- 作业2
- Codeforces 630N - Forecast
- 【HDU5638 BestCoder Round 74 (div1)C】【贪心 线段树or树套树or队列】Toposort n点m边删k边使得拓扑序最小
- docker 学习笔记3