卧薪尝胆,厚积薄发。
TJOI2016&HEOI2016 序列
Date: Fri Aug 10 22:39:28 CST 2018 In Category: NoCategory

Description:

一个数列,同一时刻只会有一个数发生变化,问在所有情况下都满足单调不降的子序列最长是几。
$1\le n \le 100000$

Solution:

树状数组最大值不是 $n$ !!!
$sort$ 之后顺序会变所以要更新对应的 $f$ !!!
前面对后面的影响所以后半部分的递归要放在函数最后!!!
$sort$ 左闭右开!!!
$f[i]=max(f[j]+1)(max[j]\le a[i],a[j]\le min[i],j<i)$
发现是一个偏序问题,直接 $cdq$ 即可。

Code:


#include<algorithm>
#include<iostream>
#include<cstdlib>
#include<cstdio>
#include<cmath>
#include<cstring>
using namespace std;
int n,m;
#define MAXN 100010
struct num
{
int id,a,maxn,minn;
}w[MAXN];
int f[MAXN];
bool cmp_maxn(num x,num y){return x.maxn < y.maxn;}
bool cmp_a(num x,num y){return x.a < y.a;}
bool cmp_id(num x,num y){return x.id < y.id;}
int mx = 0;
struct BIT
{
int c[MAXN];
int lowbit(int x){return (x&(-x));}
void add(int p,int k){for(int i = p;i <= mx;i += lowbit(i))c[i] = max(c[i],k);return;}
int query(int p){int res = 0;for(int i = p;i >= 1;i -= lowbit(i))res = max(res,c[i]);return res;}
void reset(int p){for(int i = p;i <= mx;i += lowbit(i))c[i] = 0;return;}
}t;
void cdq(int l,int r)
{
if(l == r)return;
int mid = (l + r) / 2;
cdq(l,mid);
sort(w + l,w + mid + 1,cmp_maxn);
sort(w + mid + 1,w + r + 1,cmp_a);
int i = l,j = mid + 1;
for(;i <= mid && j <= r;)
{
if(w[i].maxn > w[j].a)
{
f[w[j].id] = max(f[w[j].id],t.query(w[j].minn) + 1);
++j;
}
else
{
t.add(w[i].a,f[w[i].id]);
++i;
}
}
for(;j <= r;++j)f[w[j].id] = max(f[w[j].id],t.query(w[j].minn) + 1);
for(int k = l;k <= mid;++k)t.reset(w[k].a);
sort(w + mid + 1,w + r + 1,cmp_id);
cdq(mid + 1,r);
return;
}
int main()
{
scanf("%d%d",&n,&m);
for(int i = 1;i <= n;++i)
{
scanf("%d",&w[i].a);
w[i].minn = w[i].maxn = w[i].a;
f[i] = 1;
w[i].id = i;
mx = max(mx,w[i].a);
}
int p,k;
for(int i = 1;i <= m;++i)
{
scanf("%d%d",&p,&k);
w[p].minn = min(w[p].minn,k);
w[p].maxn = max(w[p].maxn,k);
mx = max(mx,k);
}
cdq(1,n);
int ans = 0;
for(int i = 1;i <= n;++i)
ans = max(ans,f[i]);
cout << ans << endl;
return 0;
}
Copyright © 2020 wjh15101051
ღゝ◡╹)ノ♡