[CEOI2018]Global warming
[CEOI2018]Global warming
题目大意:
给定\(n(n\le2\times10^5)\),你可以将任意\(a_{l\sim r}(1\le l\le r\le n)\)每一个元素加上一个\(d(|d|\le x)\),求\(a\)的LIS长度。
思路:
不难发现区间加一个数是为了使得LIS中间一段比左边一段大,而右边一段本来就比中间的大,那么我们给右边一段同时加上也不会影响答案。因此我们可以给一个后缀加上\(x\)求LIS即可。
用两个树状数组分别维护,当前是否是已被增加过的后缀,前缀LIS的最大值。
时间复杂度\(\mathcal O(n\log n)\)。
源代码:
#include<cstdio>
#include<cctype>
#include<algorithm>
inline int getint() {
register char ch;
while(!isdigit(ch=getchar()));
register int x=ch^'0';
while(isdigit(ch=getchar())) x=(((x<<2)+x)<<1)+(ch^'0');
return x;
}
const int N=2e5+1;
int a[N],tmp[N*2];
class SegmentTree {
private:
int val[N*2];
int lowbit(const int &x) const {
return x&-x;
}
public:
void modify(int p,const int &x) {
for(;p<=tmp[0];p+=lowbit(p)) {
val[p]=std::max(val[p],x);
}
}
int query(int p) const {
int ret=0;
for(;p;p-=lowbit(p)) {
ret=std::max(ret,val[p]);
}
return ret;
}
};
SegmentTree t[2];
int main() {
const int n=getint(),x=getint();
for(register int i=1;i<=n;i++) {
tmp[i]=a[i]=getint();
tmp[n+i]=a[i]+x;
}
std::sort(&tmp[1],&tmp[n*2]+1);
tmp[0]=std::unique(&tmp[1],&tmp[n*2]+1)-&tmp[1];
for(register int i=1;i<=n;i++) {
const int pos1=std::lower_bound(&tmp[1],&tmp[tmp[0]]+1,a[i]+x)-tmp;
t[1].modify(pos1,t[0].query(pos1-1)+1);
t[1].modify(pos1,t[1].query(pos1-1)+1);
const int pos0=std::lower_bound(&tmp[1],&tmp[tmp[0]]+1,a[i])-tmp;
t[0].modify(pos0,t[0].query(pos0-1)+1);
}
printf("%d\n",t[1].query(tmp[0]));
return 0;
}