您的位置:首页 > 其它

codeforces 650D. Zip-line 线段树

2016-03-09 09:24 441 查看
题目链接

题目的意思很简单, 就是给你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;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: