zoukankan      html  css  js  c++  java
  • [Gym101821B] LIS vs. LDS

    传送门

    随便找一个 LIS 和 LDS,发现最多有一个元素相交。

    将折线图画出来,发现上面的情况中,两条折线在某个折点处相交。

    然后发现我们想要的解是两条折线交点在某两个元素之间的情况。(不交的可以看作在 ((0, 1)) 或者 ((n, n+1)) 之间交了)

    那就枚举交点的位置在哪两个元素之间,并考虑交点的大小在哪两个整数之间。

    假设交点的位置是 (pin(i, i+1)),大小是 (xin(j, j+1)),那么必然是在 ([1, i]) 和左右翻转后的 ([i+1, n]) 内,各选一个末尾元素不超过 (j) 的 LIS 和一个末尾元素不小于 (j+1) 的 LDS。以 (x) 为下标建立线段树,在交点位置移动时维护每个下标对应四个值的和的最大值。

    由于四个值是对称的,这里只考虑交点位置移动时,在 ([1, i]) 中取一个不超过 (j) 的 LIS 的变化情况。考虑正常求 LIS 的过程,令 (f_i) 为长度为 (i) 的 LIS 的末尾元素最小值,则 (f_i) 不超过 (x)(i) 的个数即为答案。末尾添加元素 (a) 的时候,会使最小的 (f_kgeq a) 变为 (a),也就是给 ([a, f_k]) 这段值域区间的答案 (+1)。其余同理,预处理变化元素的位置和值即可。

    代码细节比较多,也可能只是我写麻烦了……

    顺便这题在某 OJ 上的魔改版,无解也要构造……太毒瘤了(

    #include <bits/stdc++.h>
    #define R register
    #define mp make_pair
    #define ll long long
    #define pii pair<int, int>
    using namespace std;
    const int N = 510000;
    
    int n, p[N], fr[N], gr[N], fbc[N], gbc[N], f[N], g[N], a[N], fl[N], gl[N], ans1[N], ans2[N];
    
    struct segmentTree {
    //
    #define mid ((lt[k] + rt[k]) >> 1)
    #define l (k << 1)
    #define r (k << 1 | 1)
    static const int K = N << 2;
    
    int lt[K], rt[K], maxV[K], add[K], maxLb[K];
    
    inline void init(int n, int *a) {
    	lt[1] = 1, rt[1] = n, build(1, a);
    	return;
    }
    
    inline void update(int k) {
    	if (maxV[r] > maxV[l]) maxV[k] = maxV[r], maxLb[k] = maxLb[r];
    	else maxV[k] = maxV[l], maxLb[k] = maxLb[l];
    	return;
    }
    
    void build(int k, int *a) {
    	if (lt[k] == rt[k]) {
    		maxV[k] = a[lt[k]], maxLb[k] = lt[k];
    		return;
    	}
    	lt[l] = lt[k], rt[l] = mid, lt[r] = mid + 1, rt[r] = rt[k];
    	return build(l, a), build(r, a), update(k);
    }
    
    void modify(int k, int x, int y, int w) {
    	if (lt[k] >= x && rt[k] <= y) {
    		add[k] += w, maxV[k] += w;
    		return;
    	}
    	pushdown(k);
    	if (x <= mid) modify(l, x, y, w);
    	if (y > mid) modify(r, x, y, w);
    	return update(k);
    }
    
    inline void pushdown(int k) {
    	if (add[k]) {
    		modify(l, lt[k], rt[k], add[k]);
    		modify(r, lt[k], rt[k], add[k]);
    		add[k] = 0;
    	}
    	return;
    }
    
    inline pii query() {
    	return mp(maxV[1], maxLb[1]);
    }
    
    #undef mid
    #undef l
    #undef r
    //
    } seg;
    
    template <class T>
    inline void read(T &x) {
    	x = 0;
    	char ch = getchar(), w = 0;
    	while (!isdigit(ch)) w = (ch == '-'), ch = getchar();
    	while (isdigit(ch)) x = (x << 1) + (x << 3) + (ch ^ 48), ch = getchar();
    	x = w ? -x : x;
    	return;
    }
    
    int main() {
    	read(n);
    	for (R int i = 1; i <= n; ++i) read(p[i]), f[i] = g[i] = n + 1;
    	int n1 = 0, n2 = 0;
    	for (R int i = n; i; --i) {
    		fr[i] = lower_bound(f + 1, f + 1 + n1, p[i]) - f;
    		gr[i] = lower_bound(g + 1, g + 1 + n2, n + 1 - p[i]) - g;
    		n1 = max(n1, fr[i]), n2 = max(n2, gr[i]);
    		fbc[i] = f[fr[i]], gbc[i] = g[gr[i]];
    		f[fr[i]] = p[i], g[gr[i]] = n + 1 - p[i];
    	}
    	f[n + 1] = n + 1;
    	for (R int i = 1, tl1 = 1, tl2 = n; i <= n + 1; ++i) {
    		while (f[tl1] < i) ++tl1;
    		while (g[tl2] > n + 1 - i) --tl2;
    		a[i] = tl1 + tl2 - 1;
    	}
    	for (R int i = 1; i <= n + 1; ++i) f[i] = g[i] = n + 1;
    	seg.init(n + 1, a);
    	int pos = 0;
    	pii ans = seg.query(), tmp;
    	// x >= i -> n+1-x <= n+1-i -> y <= n+1-i -> i <= n+1-y
    	for (R int i = 1; i <= n; ++i) {
    		fl[i] = lower_bound(f + 1, f + 1 + n, p[i]) - f;
    		gl[i] = lower_bound(g + 1, g + 1 + n, n + 1 - p[i]) - g;
    		if (f[fl[i]] < fbc[i]) seg.modify(1, f[fl[i]] + 1, fbc[i], -1);
    		else if (f[fl[i]] > fbc[i]) seg.modify(1, fbc[i] + 1, f[fl[i]], 1);
    		if (g[gl[i]] < gbc[i]) seg.modify(1, n + 2 - gbc[i], n + 1 - g[gl[i]], -1);
    		else if (g[gl[i]] > gbc[i]) seg.modify(1, n + 2 - g[gl[i]], n + 1 - gbc[i], 1);
    		tmp = seg.query(), f[fl[i]] = p[i], g[gl[i]] = n + 1 - p[i];
    		if (ans < tmp) pos = i, ans = tmp;
    	}
    	if (ans.first != n1 + n2) return printf("IMPOSSIBLE
    "), 0;
    	for (R int i = 1; i <= n; ++i) f[i] = n + 1, g[i] = 0;
    	for (R int i = 1; i <= pos; ++i)
    		f[fl[i]] = p[i], g[gl[i]] = p[i];
    	int kl = 0, kr = 0;
    	while (kl < n && f[kl + 1] < ans.second) ++kl;
    	while (kr < n && g[kr + 1] >= ans.second) ++kr;
    	for (R int i = pos, tl = kl, tr = kr; i; --i) {
    		if (fl[i] == tl) ans1[tl] = i, --tl;
    		if (gl[i] == tr) ans2[n1 - tr + 1] = i, --tr;
    	}
    	for (R int i = pos + 1, tl = n2 - kl, tr = n1 - kr; i <= n; ++i) {
    		if (fr[i] == tr) ans2[tr] = i, --tr;
    		if (gr[i] == tl) ans1[n2 - tl + 1] = i, --tl;
    	}
    	printf("%d
    ", n2);
    	for (R int i = 1; i <= n2; ++i) printf("%d ", ans1[i]);
    	printf("
    %d
    ", n1);
    	reverse(ans2 + 1, ans2 + n1 + 1);
    	for (R int i = 1; i <= n1; ++i) printf("%d ", ans2[i]);
    	return 0;
    }
    
  • 相关阅读:
    通用的web系统数据导出功能设计实现(导出excel2003/2007 word pdf zip等)
    DALSA Coreco
    环境变量之执行文件路径的变量PATH
    命令与文件的查询
    软件开发工具GCC
    权限与命令之间的关系
    Linux防火墙
    网络管理
    分区及格式化
    VMware Workstation的网络连接方式:NAT、桥接和Host Only
  • 原文地址:https://www.cnblogs.com/suwakow/p/12364651.html
Copyright © 2011-2022 走看看