题面
Sol
处理出每个数(p[i])最大能变成多少和最小能变成多少(mx[i], mn[i])
设(f[i])表示到第(i)个位置的最长的满足要求的序列
(f[i]=max(f[j])+1)满足(mx[j]le p[i])且(p[j] le mn[i])
然后这个东西类似三维偏序,可以在线树套树维护
或者(CDQ)分治来搞
(CDQ)分治时,可以先把左边按(p)从小到大排序,右边按(mn)排
然后双端点移动,树状数组统计
注意分治完左边后不能立刻分治右边,必须按照中序遍历,做完这一层再分治右边
因为这一层的(DP)值会对右边产生影响
还要注意(DP)值要取(max)
这个很显然然而没取(WA)了一遍
# include <bits/stdc++.h>
# define RG register
# define IL inline
# define Fill(a, b) memset(a, b, sizeof(a))
using namespace std;
const int _(1e5 + 5);
typedef long long ll;
IL int Input(){
RG int x = 0, z = 1; RG char c = getchar();
for(; c < '0' || c > '9'; c = getchar()) z = c == '-' ? -1 : 1;
for(; c >= '0' && c <= '9'; c = getchar()) x = (x << 1) + (x << 3) + (c ^ 48);
return x * z;
}
int n, m, f[_], ans, mx[_];
struct Point{
int id, p, mn, mx;
} p[_];
IL void Add(RG int x, RG int v){
for(; x <= n; x += x & -x) mx[x] = max(mx[x], v);
}
IL void Cls(RG int x){
for(; x <= n; x += x & -x) mx[x] = 0;
}
IL int Query(RG int x){
RG int ret = 0;
for(; x; x -= x & -x) ret = max(ret, mx[x]);
return ret;
}
IL int Cmp1(RG Point A, RG Point B){
return A.id < B.id;
}
IL int Cmp2(RG Point A, RG Point B){
return A.p < B.p;
}
IL int Cmp3(RG Point A, RG Point B){
return A.mn < B.mn;
}
IL void CDQ(RG int l, RG int r){
if(l == r) return;
RG int mid = (l + r) >> 1;
CDQ(l, mid);
sort(p + l, p + mid + 1, Cmp2), sort(p + mid + 1, p + r + 1, Cmp3);
for(RG int i = mid + 1, j = l; i <= r; ++i){
while(p[j].p <= p[i].mn && j <= mid) Add(p[j].mx, f[p[j].id]), ++j;
f[p[i].id] = max(f[p[i].id], Query(p[i].p) + 1);
}
for(RG int i = l; i <= mid; ++i) Cls(p[i].mx);
sort(p + mid + 1, p + r + 1, Cmp1), CDQ(mid + 1, r);
}
int main(RG int argc, RG char* argv[]){
n = Input(), m = Input();
for(RG int i = 1; i <= n; ++i)
f[i] = 1, p[i].id = i, p[i].p = p[i].mx = p[i].mn = Input();
for(RG int i = 1; i <= m; ++i){
RG int x = Input(), y = Input();
p[x].mn = min(p[x].mn, y), p[x].mx = max(p[x].mx, y);
}
CDQ(1, n);
for(RG int i = 1; i <= n; ++i) ans = max(ans, f[i]);
printf("%d
", ans);
return 0;
}