首页 > 其他分享 >ARC167D Good Permutation 题解

ARC167D Good Permutation 题解

时间:2023-12-27 10:34:48浏览次数:26  
标签:pii Good int 题解 mn fa set ARC167D find

ARC167D

看到排列并且有 \(i\gets a_i\),就可以直接建出图来,显然是若干个不相干的环。

如果不求字典序最小,就可以直接不在同一个环中的 \(i,j\) 直接交换就可以了,因为它要求了最小化操作数。如果求字典序最小,直接从前往后扫一遍,可以用 set 维护不在这个环中且 \(j>i\) 的最小值,如果小于当前的 \(a_i\) 就可以直接交换。但注意如果这是这个环的最后一个数,就必须要交换。

时间复杂度:\(\mathcal{O}(n\log n)\)。空间线性。

更优的做法是因为最小值有单调性,就可以不用 set,直接扫一遍即可。

代码:

const int N=2e5+10;
int n;
int a[N],fa[N],sz[N],mn[N],pos[N];
set<pii> s;
typedef set<pii>::iterator iter;
int find(int x){return fa[x]==x?x:fa[x]=find(fa[x]);}
void merg(int u,int v){
	u=find(u),v=find(v);
	if(u!=v){
		fa[u]=v,sz[v]+=sz[u];
		s.erase(pii(mn[u],u));
		s.erase(pii(mn[v],v));
		s.insert(pii((mn[v]=min(mn[u],mn[v])),v));
	}
}
void solve(){
	cin>>n;
	s.clear();
	for(int i=1;i<=n;i++)cin>>a[i],fa[i]=mn[i]=i,pos[a[i]]=i,sz[i]=1,s.insert(pii(mn[i],i));
	for(int i=1;i<=n;i++)merg(a[i],i);
	for(int i=1;i<=n&&s.size()>1;i++){
		iter it=s.begin();
		while(find(it->second)==find(i))it++;
		int v=it->first,p=pos[it->first];
		if(v<a[i]||sz[find(i)]==1){
			swap(a[i],a[p]);swap(pos[a[i]],pos[a[p]]);
			merg(i,p);
		}
		sz[find(i)]--;
	}
	for(int i=1;i<=n;i++)cout<<a[i]<<" ";cout<<"\n";
}
int main(){
	ios::sync_with_stdio(0);cin.tie(0);
	int T;cin>>T;
	while(T--)solve();
	return 0;
}

标签:pii,Good,int,题解,mn,fa,set,ARC167D,find
From: https://www.cnblogs.com/Pengzt/p/17929982.html

相关文章

  • ARC105E Keep Graph Disconnected 题解
    ARC105E正向考虑是很难的,从结果入手,发现最后一定是分别包含\(1\),\(n\)的两个完全图。考虑表示出这两个人一共加了多少边:\(\frac{n(n-1)}{2}-m-x(n-x)\),\(x\)表示点\(1\)所在集合的大小。由于是判断先手还是后手必胜,所以只需看结果对\(2\)的余数,于是对\(n\)的奇偶进行......
  • P5513 [CEOI2013] Board 题解
    P5513容易发现,每次等价于对一个二进制数进行操作。但是这个二进制数长为\(n\),即需要高精。但是这样支持加一和减一是复杂度会退化为\(\mathcal{O}(n^2)\),有一个很正常的做法就压位,仿照bitset的做法进行操作,复杂度\(\mathcal{O}(\frac{n^2}{w})\)。这样已经可以通过了,但发......
  • 模拟赛简要题解
    11.16(C0389)100+10+50=160,rk3。本来BC都应该写出来的。A:dp或贪心都可以,贪心直接从下往上覆盖即可。B:注意:这里的\(\oplus\)指的是按位或。合法条件可以化简为:\(\oplus_{i=1}^{p}a_i=\oplus_{i=p+1}^{n}a_i\)。继续挖掘。看到位运算肯定想到拆位,考虑每一位第一次和......
  • 【数据结构】P4338 [ZJOI2018] 历史 题解
    P4338先考虑怎么安排崛起的先后顺序最优。但是发现好像没有一个很好的顺序去进行崛起,并且由于\(a_i\)的值域会很大,所以即使知道顺序应该也会难以进行维护。转换一下方向,正难则反。考虑每个点的贡献,但是颜色不同时只会算一次,所以要钦定是哪一个点造成的贡献。令当前考虑的点为......
  • CF1896D Ones and Twos 题解
    CF1896D如果只有单次询问其实可以双指针,但是这个难以进行拓展。考虑找点性质。发现\(a_i,v\in\{1,2\}\),从值域上下手。发现若存在和为\(S\)的方案,则一定有和为\(S-2\)的方案,因为可以直接\(-2\)或\(-1-1\)。然后就变为找最大的和为奇/偶数了,因为如果最大的都不行就肯定......
  • P9032 [COCI2022-2023#1] Neboderi 题解
    P9032考试题。发现\(g\)的值是若干个相同的段,且段数很少,因为每次取\(\gcd\)至少会将值域变为原来的一半。所以段数是\(\mathcal{O}(\logV)\)的。然后就可以从小到大枚举左端点,然后枚举\(g\)的值,找的是最远的满足\(\gcd(a_l,\dots,a_r)=g\)的\(r\),这里可以使用二分......
  • [CTSC2018]暴力写挂题解
    我们先将柿子变成\(\frac{1}{2}(dis_{x,y}+dep_{x}+dep_{y})-dep'_{lca'}\)考虑边分治,枚举断边,我们将一个点在第二棵树上的点权看成是\(v_x=d_x+dep_x\),答案就为\(v_x+v_y+dep'_{lca'}\)对于每次边分治将分治联通块内所有点在第二棵树上的建出虚树,同时将分治联通块以分治中心......
  • CF1887D Split 题解
    Problem-D-CodeforcesSplit-洛谷我现在水平好烂,再做下去自信心就全败没了先考虑\(Q=1\)怎么做?两种做法:暴力枚举分界点,左右判断暴力枚举\(\max\limits_{i=l}^{x}a_i\),找到最靠右边的分界点位置\(x\),判断是否\(\max\limits_{i=l}^{x}a_i<\min\limits......
  • [ABC267F] Exactly K Steps 题解
    [ABC267F]ExactlyKSteps题解思路首先发现,如果对于查询\((u,k),k>0\)可行,那么对于\((u,k-1)\)也一定可行,因为往回走一步就可以了,所以对于一个点可以找到离它最远的点,根据直径的结论,这个点一定是直径的端点之一。为了方便做,以直径的端点之一为根,然后写一个K级祖......
  • 【CF30E】Tricky and Clever Password 题解(manacher + exKMP)
    manacher+exKMP+二分。感觉是最粗暴的方法,想出来之后自己硬莽了4k,荣获题解区最长。Solution约定:下文所提及到的所有的回文串,均指奇长度回文串。显然把题目拆成两个部分,中间的回文串,以及两边相同的连续子串。考虑一下从哪个入手比较好。忘记是咋想的了,易得从两边相同......