http://cplusoj.com/d/senior/p/SS241007B
显然这题是一个二维数点问题,我们要求在确定 [ l , r ] [l,r] [l,r] 下 i i i 个数的最大值:
- l < i < r l<i<r l<i<r
- a r < i < a l a_r<i<a_l ar<i<al
考场上想了各种扫描线,cdq,kdtree,可持久化,树套树都想不起这个套路是啥,这其实是一个经典的套路,窗口的星星
矩阵和点的相互转化
而在此题,我们也就看每个 i i i 能作用哪些 [ l , r ] [l,r] [l,r],我们把这个覆盖区域变成一个矩形,那么就是求最多矩形覆盖的有多少,这个可以就是裸的二维数点了
而为了让它张成一个矩形,我们发现只需要维护前后的上升/下降序列作为关键点即可
#include<bits/stdc++.h>
using namespace std;
#ifdef LOCAL#define debug(...) fprintf(stdout, ##__VA_ARGS__)#define debag(...) fprintf(stderr, ##__VA_ARGS__)
#else#define debug(...) void(0)#define debag(...) void(0)
#endif
#define int long long
inline int read(){int x=0,f=1;char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')f=-1;
ch=getchar();}while(ch>='0'&&ch<='9'){x=(x<<1)+
(x<<3)+(ch^48);ch=getchar();}return x*f;}
#define Z(x) (x)*(x)
#define pb push_back
#define fi first
#define se second
//#define M
//#define mo
#define N 1000010
int n, m, i, j, k, T;
int a[N], x, y, s1, s2;
int lmx[N], rmx[N], lst, ans; int find_L(int i) {int l = 1, r = lmx[i], mid; while(l < r) {mid = (l + r) >> 1; if(a[lmx[mid]] >= a[i]) r = mid; else l = mid + 1; }return l;
}int find_R(int i) {int l = rmx[i], r = n, mid; while(l < r) {mid = (l + r + 1) >> 1; if(a[rmx[mid]] <= a[i]) l = mid; else r = mid - 1; }return r;
}namespace Scan {struct Segment_tree {#define ls (k << 1)#define rs (k << 1 | 1) #define mid ((l + r) >> 1)int tag[N << 2], mx[N << 2]; void push_down(int k) {tag[ls] += tag[k]; tag[rs] += tag[k]; mx[ls] += tag[k]; mx[rs] += tag[k]; tag[k] = 0; }void add(int k, int l, int r, int x, int y, int z) {if(l >= x && r <= y) return tag[k] += z, mx[k] += z, void(); push_down(k); if(x <= mid) add(ls, l, mid, x, y, z); if(y >= mid + 1) add(rs, mid + 1, r, x, y, z); mx[k] = max(mx[ls], mx[rs]); }#undef ls#undef rs#undef mid}Seg;struct node { int l, r, v; };vector<node>G[N]; void insert(int lx, int ly, int rx, int ry) {
// debug("Polygon\n%lld %lld\n%lld %lld\n%lld %lld\n%lld %lld\n",
// lx, rx, lx, ry + 1, ly + 1, ry + 1, ly + 1, rx); debug("%lld %lld %lld %lld\n", lx, ly, rx, ry); G[rx].pb({lx, ly, 1}); G[ry + 1].pb({lx, ly, -1}); }int run() {int i, ans = 0; for(i = 1; i <= n; ++i) {for(auto t : G[i]) {Seg.add(1, 1, n, t.l, t.r, t.v); }ans = max(ans, Seg.mx[1]); }return ans; }
}signed main()
{freopen("inverse.in", "r", stdin);freopen("inverse.out", "w", stdout);
// srand(time(NULL));
// T = read();
// while(T--) {
//
// }n = read(); for(i = 1; i <= n; ++i) a[i] = read(); for(i = 1, lst = 0; i <= n; ++i) {if(a[i] > lst) lst = a[i], lmx[i] = i; else lmx[i] = lmx[i - 1]; }for(i = n, lst = 1e9; i >= 1; --i) {if(a[i] < lst) lst = a[i], rmx[i] = i; else rmx[i] = rmx[i + 1]; }for(i = 1; i <= n; ++i) debug("%lld ", lmx[i]); debug("\n"); for(i = 1; i <= n; ++i) debug("%lld ", rmx[i]); debug("\n"); for(i = 1; i <= n; ++i) {int L = find_L(i), R = find_R(i); Scan :: insert(L, lmx[i], rmx[i], R); }ans = Scan :: run(); printf("%lld", 2 * ans - 3); return 0;
}