The Preliminary Contest for ICPC Asia Nanjing 2019 F.Greedy Sequence(主席树上二分)

Posted issue是fw

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了The Preliminary Contest for ICPC Asia Nanjing 2019 F.Greedy Sequence(主席树上二分)相关的知识,希望对你有一定的参考价值。

LINK

Ⅰ. s i , 1 = i s_{i,1}=i si,1=i

Ⅱ. s i , j < = s i , j − 1 s_{i,j}<=s_{i,j-1} si,j<=si,j1

Ⅲ. s i , j s_{i,j} si,j在数组 a a a中的位置是 p o s j pos_j posj,那么 ∣ p o s j − p o s j − 1 ∣ < = k |pos_j-pos_{j-1}|<=k posjposj1<=k

Ⅳ. s i s_i si应该在字典序上最大

Ⅴ.设此时 s i s_i si的长度为 k k k,在后面补齐 n − k n-k nk 0 0 0

先考虑第一个元素为 n n n的情况,设其在 a a a数组中出现位置为 f f f

此时需要找到范围 [ f − k , f + k ] [f-k,f+k] [fk,f+k]中第一个小于 n n n的数字

这个过程可以用主席树完成,设找到的数字为 n − 3 n-3 n3

那么 s n − 3 s_{n-3} sn3的答案就是 s n s_n sn的答案减一

综上所诉,只需要对每个数字标记以下以它开头的答案是多少即可

总复杂度 O ( n l o g ( n ) ) O(nlog(n)) O(nlog(n))

在主席树上二分即可

#include <bits/stdc++.h>
using namespace std;
#define mid (l+r>>1)
const int maxn = 2e5+10;
int a[maxn],pos[maxn],ans[maxn],n,k;
//*20,也就是2,4,8,16,2^32 
int rt[maxn<<5],ls[maxn<<5],rs[maxn<<5],sum[maxn<<5],id; 
void insert(int &rt,int pre,int l,int r,int val)
{
	if( l>val || r<val )	return;
	rt = ++id;
	ls[rt] = ls[pre], rs[rt] = rs[pre], sum[rt] = sum[pre];
	if( l==r && l==val ){ sum[rt] = 1; return;}
	insert( ls[rt],ls[pre],l,mid,val); insert( rs[rt],rs[pre],mid+1,r,val );
	sum[rt] = sum[ls[rt]]+sum[rs[rt]];
}
int ask(int rt,int pre,int l,int r,int L,int R)
{
	if( l>R || r<L )	return 0;//没找到的意思 
	if( l>=L && r<=R )
	{
		if( l==r )
		{
			if( sum[rt]-sum[pre] )	return l;
			else	return 0;	
		}	
		int x = sum[rs[rt]]-sum[rs[pre]];
		int op = ask( rs[rt],rs[pre],mid+1,r,L,R );
		if( op )	return op;
		else	return ask( ls[rt],ls[pre],l,mid,L,R );
	}
	else
	{
		int w = ask( rs[rt],rs[pre],mid+1,r,L,R );
		if( w )	return w;
		else	return ask( ls[rt],ls[pre],l,mid,L,R );
	}
}
int main()
{
	int t; cin >> t;
	while( t-- )
	{
		cin >> n >> k;
		for(int i=1;i<=n;i++)
		{
			cin >> a[i]; pos[a[i]] = i;
			insert( rt[i],rt[i-1],1,n,a[i] );
		}
		ans[1] = 1;
		for(int i=2;i<=n;i++)
		{
			int l = max(1,pos[i]-k), r = min( n,pos[i]+k );
			int x = ask( rt[r],rt[l-1],1,n,1,i-1);
			ans[i] = ans[x]+1;
		}
		for(int i=1;i<=n;i++)	printf("%d%c",ans[i],i==n?'\\n':' ');
		
		for(int i=1;i<=id;i++)	sum[i] = ls[i] = rs[i] = rt[i] =  0;
		id = 0;
	}	
	return 0;
}

以上是关于The Preliminary Contest for ICPC Asia Nanjing 2019 F.Greedy Sequence(主席树上二分)的主要内容,如果未能解决你的问题,请参考以下文章

The Preliminary Contest for ICPC Asia Yinchuan 2019

The Preliminary Contest for ICPC Asia Shenyang 2019

The Preliminary Contest for ICPC Asia Shanghai 2019

The Preliminary Contest for ICPC Asia Shanghai 2019

The Preliminary Contest for ICPC Asia Xuzhou 2019

The Preliminary Contest for ICPC Asia Nanchang 2019