JZOJ5920. 【NOIP2018模拟10.22】风筝

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/XLno_name/article/details/83310745

题意:

当一阵风吹来,风筝飞上天空,为了你,而祈祷,而祝福,而感动……
oyiya 在 AK 了 IOI 之后来到了乡下,在田野中玩耍,放松身心。
他发现前面有一排小朋友在放风筝,每一个风筝有一个高度 h i h_i ,风筝的高度可能会随着小朋友的心情而改变。这时,毒瘤的 oyiya 有了一个毒瘤的 idea,他想知道改变高度之后风筝的最长严格上升子序列。oyiya 太强了表示并不想做这种水题,你能解决这个问题吗?

数据范围:


时限4S。

Analysis:

观察一波,可以发现经过修改点的LIS可以拼接,关键是求其是否在原序列所有LIS中。
仔细分析,此时可以有两个性质:
1.若一个数在所有LIS中,则其在LIS中排名固定,且唯一,若有数与其处于同一排名,则其不在所有LIS中。
2.若一个数不所有LIS中,其左边有不小于它的数在LIS中,或其右边有不大于它的数在LIS中。

那么根据这两条性质,就可以求出这个了,然后分类讨论一波即可:
我用的是第二条性质。

Code:

# include<cstdio>
# include<cstring>
# include<algorithm>
# include<vector>
using namespace std;
# define pb push_back
const int N = 2e6 + 5;
struct node
{
	int x,id;
};
vector <node> q[N];
int t[N << 1],h[N],a[N << 1],is[N],no[N],f[N],ans[N];
int n,m,len,all;
inline int read()
{
	int x = 0; char ch = getchar();
	for (; ch < '0' || ch > '9' ; ch = getchar());
	for (; ch >= '0' && ch <= '9' ; ch = getchar()) x = x * 10 + ch - '0';
	return x;
}
bool cmp(int a,int b) { return a < b; }
inline void add(int x,int v)
{ for (int i = x ; i <= len ; i += i & (-i)) t[i] = max(t[i],v); }
inline int qry(int x)
{
	int ret = 0;
	for (int i = x ; i ; i -= i & (-i)) ret = max(ret,t[i]);
	return ret;
}
int main()
{
	freopen("kite.in","r",stdin);
	freopen("kite.out","w",stdout);
	n = read(),m = read();
	for (int i = 1 ; i <= n ; ++i) h[++len] = a[i] = read();
	for (int i = 1 ; i <= m ; ++i)
	{
		int pos = read(),x = read();
		h[++len] = x,q[pos].pb((node){x,i});
	}
	sort(h + 1,h + len + 1,cmp); len = unique(h + 1,h + len + 1) - h - 1;
	for (int i = 1 ; i <= n ; ++i)
	{
		int now = lower_bound(h + 1,h + len + 1,a[i]) - h;
		add(now,qry(now - 1) + 1);
	} all = qry(len);
	memset(t,0,sizeof(t));
	for (int i = 1 ; i <= n ; ++i)
	{
		int now = lower_bound(h + 1,h + len + 1,a[i]) - h;
		if (qry(len) == all) no[i] = 1; f[i] = qry(now - 1) + 1,add(now,f[i]);
	} memset(t,0,sizeof(t));
	for (int i = n ; i ; --i)
	{
		int now = len - (lower_bound(h + 1,h + len + 1,a[i]) - h) + 1,c = qry(now - 1) + 1;
		if (qry(len) == all) no[i] = 1;
		f[i] += c - 1,add(now,c); if (f[i] == all) is[i] = 1;
	}
	memset(t,0,sizeof(t));
	for (int i = 1 ; i <= n ; ++i)
	{
		int now = len - (lower_bound(h + 1,h + len + 1,a[i]) - h) + 1;
		no[i] |= qry(now),add(now,is[i]);
	} memset(t,0,sizeof(t));
	for (int i = n ; i ; --i)
	{
		int now = lower_bound(h + 1,h + len + 1,a[i]) - h;
		no[i] |= qry(now),add(now,is[i]);
	} memset(t,0,sizeof(t));
	for (int i = 1 ; i <= n ; ++i)
	{
		for (int j = 0 ; j < q[i].size() ; ++j)
		{
			int now = lower_bound(h + 1,h + len + 1,q[i][j].x) - h;
			ans[q[i][j].id] = qry(now - 1);
		}
		int now = lower_bound(h + 1,h + len + 1,a[i]) - h;
		add(now,qry(now - 1) + 1);
	} memset(t,0,sizeof(t));
	for (int i = n ; i ; --i)
	{
		for (int j = 0 ; j < q[i].size() ; ++j)
		{
			int now = len - (lower_bound(h + 1,h + len + 1,q[i][j].x) - h) + 1;
			ans[q[i][j].id] += qry(now - 1) + 1;
			if (no[i]) ans[q[i][j].id] = max(ans[q[i][j].id],all);
			else ans[q[i][j].id] = max(ans[q[i][j].id],all - 1);
		}
		int now = len - (lower_bound(h + 1,h + len + 1,a[i]) - h) + 1;
		add(now,qry(now - 1) + 1);
	}
	for (int i = 1 ; i <= m ; ++i) printf("%d\n",ans[i]);
	return 0;
}

猜你喜欢

转载自blog.csdn.net/XLno_name/article/details/83310745