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(主席树上二分)的主要内容,如果未能解决你的问题,请参考以下文章