codeforces 650D. Zip-line 线段树
题目的意思很简单, 就是给你n个数, m个询问, 每次询问修改某一个位置的值, 然后问你修改完之后数列的lis是多少。 询问独立。
对于原数列, 我们将它离散化, 令dp1[i]为以i为结尾位置的最长上升子序列的长度, dp[2]为以i结尾的从后往前的最长下降子序列的长度。
原数列的lis显然为max(dp1[i]+dp2[i]-1)。
然后我们求出哪些位置是关键位置, 所谓关键位置, 就是说如果把这个位置的值改变, 那么lis的值也许就会减1。 求关键位置的方法看代码。
然后对于每个询问, 令x[i]为位置, y[i]为修改后并离散化的值,我们令dp3[i]表示将x[i]位置修改为y[i]之后, 以x[i]结尾的最长上升子序列的长度, dp4[i]为最长下降的长度。
那么对于每次询问, 如果x[i]是关键节点, ans[i] = max(lis-1, dp3[i]+dp4[i]-1), 否则的话, ans[i] = max(lis, dp3[i]+dp4[i]-1)。
具体的可以看代码。
还有一点要注意的是数组不能开成4e5, 要开成8e5。
#include <iostream> #include <vector> #include <cstdio> #include <cstring> #include <algorithm> #include <cmath> #include <map> #include <set> #include <string> #include <queue> #include <stack> #include <bitset> using namespace std; #define pb(x) push_back(x) #define ll long long #define mk(x, y) make_pair(x, y) #define lson l, m, rt<<1 #define mem(a) memset(a, 0, sizeof(a)) #define rson m+1, r, rt<<1|1 #define mem1(a) memset(a, -1, sizeof(a)) #define mem2(a) memset(a, 0x3f, sizeof(a)) #define rep(i, n, a) for(int i = a; i<n; i++) #define fi first #define se second typedef pair<int, int> pll; const double PI = acos(-1.0); const double eps = 1e-8; const int mod = 1e9+7; const int inf = 1061109567; const int dir[][2] = { {-1, 0}, {1, 0}, {0, -1}, {0, 1} }; const int maxn = 8e5+5; int sum[maxn<<2], num[maxn], dp1[maxn], dp2[maxn], dp3[maxn], dp4[maxn], a[maxn], b[maxn]; int x[maxn], y[maxn], ans[maxn]; vector <pll> v[maxn]; void update(int p, int val, int l, int r, int rt) { if(l == r) { sum[rt] = max(sum[rt], val); return ; } int m = l+r>>1; if(p<=m) update(p, val, lson); else update(p, val, rson); sum[rt] = max(sum[rt<<1],sum[rt<<1|1]); } int query(int L, int R, int l, int r, int rt) { if(L>R) return 0; if(L<=l&&R>=r) { return sum[rt]; } int m = l+r>>1, ret = 0; if(L<=m) ret = query(L, R, lson); if(R>m) ret = max(ret, query(L, R, rson)); return ret; } int main() { int n, m, cnt = 0; cin>>n>>m; for(int i = 1; i<=n; i++) { scanf("%d", &a[i]); b[cnt++] = a[i]; } for(int i = 0; i<m; i++) { scanf("%d%d", &x[i], &y[i]); b[cnt++] = y[i]; v[x[i]].pb(mk(i, y[i])); } sort(b, b+cnt); cnt = unique(b, b+cnt)-b; for(int i = 1; i<=n; i++) { a[i] = lower_bound(b, b+cnt, a[i])-b+1; } for(int i = 1; i<=n; i++) { dp1[i] = query(1, a[i]-1, 1, cnt, 1)+1; for(int j = 0; j<v[i].size(); j++) { int tmp = v[i][j].fi; int tmpy = lower_bound(b, b+cnt, v[i][j].se)-b+1; dp3[tmp] = query(1, tmpy-1, 1, cnt, 1)+1; } update(a[i], dp1[i], 1, cnt, 1); } mem(sum); for(int i = n; i>=1; i--) { dp2[i] = query(a[i]+1, cnt, 1, cnt, 1)+1; for(int j = 0; j<v[i].size(); j++) { int tmp = v[i][j].fi; int tmpy = lower_bound(b, b+cnt, v[i][j].se)-b+1; dp4[tmp] = query(tmpy+1, cnt, 1, cnt, 1)+1; } update(a[i], dp2[i], 1, cnt, 1); } int maxx = 0; for(int i = 1; i<=n; i++) { maxx = max(dp1[i]+dp2[i]-1, maxx); //求原数列lis } for(int i = 1; i<=n; i++) { if(dp1[i]+dp2[i]-1 == maxx) { num[dp1[i]]++; //如果num[dp1[i]] == 1, 那么它就是关键节点 } } for(int i = 0; i<m; i++) { int tmp = maxx; if(dp1[x[i]]+dp2[x[i]]-1 == maxx && num[dp1[x[i]]] == 1) { tmp--; } tmp = max(tmp, dp3[i]+dp4[i]-1); ans[i] = tmp; } for(int i = 0; i<m; i++) { printf("%d\n", ans[i]); } return 0; }