首页 > 其他分享 >「CF1718D」Permutation for Burenka

「CF1718D」Permutation for Burenka

时间:2022-12-18 17:12:32浏览次数:60  
标签:std Burenka le const val 10 CF1718D Permutation include

题目

点这里看题目。


称一个数组是纯的,当且仅当其中不存在重复元素。

对于两个长度均为 \(n\) 的纯数组 \(a,b\),称它们是相似的,当且仅当:

\[\forall 1\le l\le r\le n,\arg \max_{l\le i\le r}a_i=\arg\max_{l\le j\le r}b_j \]

也即是,任意子区间内,最大值的位置相同。

现在,给定一个 \(1\sim n\) 的排列 \(p\) 和一个长度为 \(n\) 的数组 \(a\)。\(a\) 中有一些位置是正整数,表示它们已经被确定;其它位置都是 \(0\),表示它们都还没有确定。设 \(k\) 为 \(a\) 中 \(0\)​ 的个数,保证 \(k\ge 2\)

给定一个大小为 \(k-1\)​​ 的集合 \(S\)​​ 和询问次数 \(q\)​​。每次询问中,你会得到一个正整数 \(x\)​​,并判断将 \(S\cup \{x\}\)​​ 中的数填入 \(a\)​​​ 中空位后(每个数必须恰好用一次,每个空位必须填上恰好一个数),得到的新数组 \(a'\)​ 是否能够与 \(p\)​ 相似。特别地,所有询问都保证得到的 \(a'\) 一定是一个纯数组

单个测试点内有多组测试数据。

所有测试点满足 \(1\le \sum n,\sum q\le 3\times 10^5,k\ge 2;1\le a_i,x\le 10^6;\forall x\in S,1\le x\le 10^6\)​​。

分析

首先进行翻译。根据 \(\arg\max\)​ 这一条,容易想到将“相似”的判断和笛卡尔树联系起来。具体来说,我们可以猜想两个纯数组相似 \(\Leftrightarrow\) 它俩笛卡尔树完全相同

这一条证明不难。\(\Leftarrow\) 显然,而 \(\Rightarrow\) 可以用相似的关系,得到每个元素左右两侧第一个大于它的位置,有了这个信息就可以直接构建笛卡尔树。

由于 \(p\)​​ 的笛卡尔树是确定的,所以我们把结构套过来,就可以知道 \(a\)​​ 上每个元素需要满足的条件。首先,先检查已经确定的元素是否满足条件。其次,已经确定的元素可以将待定元素限制在一个区间内(注意不是一个值域的后缀!);而待定元素之间的偏序关系,可以像“冒泡排序”(指 NOI2022)那样调整,所以不需要考虑。

所以,如果 \(a_i\)​ 待定,我们就设 \(a_i\)​ 的值区间为 \([l_i,r_i]\)​。之后的问题,实质上是一个二分图匹配,而如果 \(q=1\) 则有一个朴素的 \(O(n\log n)\)​ 的贪心可供使用。怎么用它处理多次询问?

考虑先对 \(S\)​ 中的元素跑一次贪心,则此时我们相当于有一个残量网络(尽管是隐式的),其流量必须为 \(k-1\)。当我们加入 \(x\) 之后,我们只需要跑出来一条增广路即可。注意到 \(q\)​ 次询问的增广路的终点一定是同一个尚未被匹配的值区间,我们可以从这个值区间开始,倒着 BFS 出来。这样可以到达的数就可以增广,不能到达的就不能增广,于是就可以对于 \(q\) 次询问进行判定了。

虽然有区间连边,但是因为是 BFS,所以不需要数据结构优化建图,用个并查集就够了。复杂度为 \(O(n\log n+q)\)。

代码

#include <queue>
#include <cstdio>
#include <vector>
#include <utility>
#include <algorithm>

#define rep( i, a, b ) for( int i = (a) ; i <= (b) ; i ++ )
#define per( i, a, b ) for( int i = (a) ; i >= (b) ; i -- )

const int INF = 1e9;
const int MAXN = 3e5 + 5;

template<typename _T>
inline void Read( _T &x ) {
	x = 0; char s = getchar(); bool f = false;
	while( ! ( '0' <= s && s <= '9' ) ) { f = s == '-', s = getchar(); }
	while( '0' <= s && s <= '9' ) { x = ( x << 3 ) + ( x << 1 ) + ( s - '0' ), s = getchar(); }
	if( f ) x = -x;
}

template<typename _T>
inline void Write( _T x ) {
	if( x < 0 ) putchar( '-' ), x = -x;
	if( 9 < x ) Write( x / 10 );
	putchar( x % 10 + '0' );
}

template<typename _T>
inline _T Max( const _T &a, const _T &b ) {
	return a > b ? a : b;
}

template<typename _T>
inline _T Min( const _T &a, const _T &b ) {
	return a < b ? a : b;
}

typedef std :: pair<int, int> Interval;

std :: priority_queue<Interval, std :: vector<Interval>, std :: greater<Interval> > lefQ;

std :: vector<int> itvLef[MAXN << 1];

int q[MAXN << 1];
int mat[MAXN << 1], fa[MAXN << 1];

bool imp[MAXN << 1];
int val[MAXN << 1], len = 0;

int seq[MAXN], tot = 0;
int arg[MAXN];

int stk[MAXN], top = 0;
int perm[MAXN], fixed[MAXN];
int lef[MAXN], rig[MAXN];
int lch[MAXN], rch[MAXN];

bool flg = true;
int N, Q;

inline void MakeSet( const int &n ) {
	rep( i, 1, n ) fa[i] = i;
}

int FindSet( const int &u ) {
	return fa[u] == u ? u : ( fa[u] = FindSet( fa[u] ) );
}

inline void UnionSet( const int &u, const int &v ) {
	fa[FindSet( u )] = FindSet( v );
}

void DFS( const int &u, int low ) {
	lef[u] = fixed[u], rig[u] = low;
	if( fixed[u] ) low = Min( low, fixed[u] );
	if( lch[u] ) DFS( lch[u], low ), lef[u] = Max( lef[u], lef[lch[u]] );
	if( rch[u] ) DFS( rch[u], low ), lef[u] = Max( lef[u], lef[rch[u]] );
}

inline void Discrete() {
	len = 0;
	rep( i, 1, Q ) val[++ len] = arg[i];
	rep( i, 1, tot - 1 ) val[++ len] = seq[i];
	std :: sort( val + 1, val + 1 + len );
	len = std :: unique( val + 1, val + 1 + len ) - val - 1;
	rep( i, 1, Q ) arg[i] = std :: lower_bound( val + 1, val + 1 + len, arg[i] ) - val;
	rep( i, 1, tot - 1 ) seq[i] = std :: lower_bound( val + 1, val + 1 + len, seq[i] ) - val;
}

int main() {
	int T; Read( T );
	while( T -- ) {
		Read( N ), Read( Q ), tot = 0;
		rep( i, 1, N ) Read( perm[i] ), lch[i] = rch[i] = 0;
		rep( i, 1, N ) Read( fixed[i] ), tot += ! fixed[i];
		rep( i, 1, tot - 1 ) Read( seq[i] );
		rep( i, 1, Q ) Read( arg[i] );

		top = 0;
		rep( i, 1, N ) {
			while( top && perm[stk[top]] <= perm[i] ) lch[i] = stk[top --];
			if( top ) { rch[stk[top]] = i; } stk[++ top] = i;
		}
		Discrete(), DFS( stk[1], 1e9 );
		rep( i, 1, len ) imp[i] = false, itvLef[i].clear(), mat[i] = 0;
		rep( i, 1, tot - 1 ) imp[seq[i]] = true;

		flg = true;
		rep( i, 1, N ) {
			if( lef[i] > rig[i] ) { flg = false; break; }
			if( fixed[i] ) continue;
			lef[i] = std :: upper_bound( val + 1, val + 1 + len, lef[i] ) - val;
			rig[i] = std :: lower_bound( val + 1, val + 1 + len, rig[i] ) - val - 1;
			if( lef[i] > rig[i] ) { flg = false; break; }
			if( lef[i] > len || rig[i] <= 0 ) { flg = false; break; }
			itvLef[lef[i]].push_back( i );
		}
		if( ! flg ) {
			rep( i, 1, Q ) puts( "NO" );
			continue;
		}

		while( ! lefQ.empty() ) lefQ.pop();
		int lost = -1;
		rep( i, 1, len ) {
			for( const int &x : itvLef[i] )
				lefQ.push( { rig[x], x } );
			if( ! imp[i] ) continue;
			while( ! lefQ.empty() && lefQ.top().first < i ) {
				if( ~ lost ) { flg = false; break; }
				lost = lefQ.top().second, lefQ.pop();
			}
			if( ! flg || lefQ.empty() ) { flg = false; break; }
			mat[i] = lefQ.top().second, lefQ.pop();
		}
		while( ! lefQ.empty() ) {
			if( ~ lost ) { flg = false; break; }
			lost = lefQ.top().second, lefQ.pop();
		}
		if( ! flg ) {
			rep( i, 1, Q ) puts( "NO" );
			continue;
		}
		MakeSet( len + 1 );
		int h = 1, t = 0; q[++ t] = lost;
		while( h <= t ) {
			int u = q[h ++];
			for( int x = FindSet( lef[u] ) ; x <= rig[u] ; x = FindSet( x + 1 ) ) {
				UnionSet( x, x + 1 );
				if( mat[x] ) q[++ t] = mat[x];
			}
		}
		rep( i, 1, Q ) puts( fa[arg[i]] != arg[i] ? "YES" : "NO" );
	}
	return 0;
}

标签:std,Burenka,le,const,val,10,CF1718D,Permutation,include
From: https://www.cnblogs.com/crashed/p/16990573.html

相关文章

  • 题解 AGC059C【Guessing Permutation for as Long as Possible】
    problem小明有一个隐藏的排列\(p\),小红想要猜出来。现在允许小红提问,每次提问的形式是\(a_i\)和\(b_i\),然后小明会告诉小红谁大谁小。小红是个老实的人,她的询问顺序......
  • codeforces 598 div3 Minimize the Permutation(贪心找规律)
    题目大意:有n个排列数。现在定义操作:交换第i和i+1个元素。我们对每个i位置只能操作一次。问经过这种操作后,我们最少能够得到的字典序序列是多少。解题思路:我们贪心从小到大选......
  • [Typescript] Create a Union of Strings with All Possible Permutations of Two Uni
    Herewehavea Sandwich typethat'scurrentlyassignedto unknownWealsohaveacoupleofuniontypes, BreadType and Filling,thathaveseveraloptions......
  • 60. Permutation Sequence(难)
    ​​[1,2,3,…,n]​​ containsatotalof n!uniquepermutations.Bylistingandlabelingallofthepermutationsinorder,Wegetthefollowingsequence(ie,......
  • lintcode:Permutations
    Givenalistofnumbers,returnallpossiblepermutations.ChallengeDoitwithoutrecursion.1.递归classSolution{public:/***@paramnums:Alistofi......
  • lintcode: Permutations II
    Givenalistofnumberswithduplicatenumberinit.Findalluniquepermutations.可以见我的博文​​全排列实现​​classSolution{public:/***@paramnu......
  • 排列(permutation)
    排列(permutation)      用1,2,3,...,9组成3个三位数abc,def和ghi,每个数字恰好使用一次,要求abc:def:ghi=1:2:3。按照“abcdefghi”的格式输出所有解,每行一个解。【......
  • CF804E The same permutation
    首先当\(n\equiv\left\{\begin{matrix}2,3\end{matrix}\right\}\pmod4\)时,无解,因为每次操作一定会改变逆序对奇偶性。那就只剩两种情况先考虑\(n\equiv0\pmod......
  • 31. 下一个排列(stl的algorithm中next_permutation的实现)
    注:这题思路就是stl的algorithm中next_permutation的实现思路整数数组的一个 排列 就是将其所有成员以序列或线性顺序排列。例如,arr=[1,2,3] ,以下这些都可以视作 ......
  • G. Restore the Permutation
    G.RestorethePermutationAsequenceof$n$numbersiscalledpermutationifitcontainsallnumbersfrom$1$to$n$exactlyonce.Forexample,thesequences......