首页 > 其他分享 >题解:AT_abc367_e [ABC367E] Permute K times

题解:AT_abc367_e [ABC367E] Permute K times

时间:2024-08-18 11:08:45浏览次数:10  
标签:tmp int 题解 void ABC367E read abc367 Permute

题意

给你一个长度为 \(N\) 的序列 \(X\) ,其中每个元素都介于 \(1\) 和 \(N\) 之间(含),以及一个长度为 \(N\) 的序列 \(A\) 。

打印在 \(A\) 上执行以下操作 \(K\) 次的结果。

将 \(A_i\) 替换为\(A_{X_i}\)。每个操作同时进行。

思路

元素 \(i\) 经过 \(k\) 次变化后的值就是元素 \(X_i\) 经过 \(k-1\) 次变化后的值。

于是我们可以将 \(i\) 和 \(X_i\) 连边。很容易发现,每一个点的出度为 \(1\),这是一颗内向基环树。于是我们处理每一个点到环上的距离,如果距离比 \(k\) 小,那么直接倍增爬树,否则直接在树上转圈圈。

Code

// Problem: E - Permute K times
// Contest: AtCoder - AtCoder Beginner Contest 367
// URL: https://atcoder.jp/contests/abc367/tasks/abc367_e
// Memory Limit: 1024 MB
// Time Limit: 2000 ms
// 
// Powered by CP Editor (https://cpeditor.org)

#include<bits/stdc++.h>
using namespace std;
#define endl '\n'
#define int long long
namespace gtx{
//	Fast IO
	void read(int &x){
		x = 0;int h = 1;char tmp;
		do{tmp=getchar();if(tmp=='-')h*=-1;}while(!isdigit(tmp));
		while(isdigit(tmp)) x*=10,x+=tmp-'0',tmp=getchar();
		x*=h;
	}
	void read(char &x){do{x=getchar();}while(x==' '||x=='\n'||x=='\r');}
	void write(char x){putchar(x);}
	void write(int x){
		if(x<0) putchar('-'),x=-x;int st[200]={0},tot=0;
		do{st[++tot]=x%10,x/=10;} while(x);
		while(tot){putchar(st[tot--]+'0');};
	}
	void write(int x,char y){write(x);write(y);}
	const int MAXN = 2e5+10;
	const int LOGN = log2(MAXN)+10;
	int n,k;
	//DSU
	int fath[MAXN];
	int get_father(int x){
		if(x==fath[x]) return x;
		return fath[x] = get_father(fath[x]);
	}
	//Topo
	int rd[MAXN],nxt[MAXN],ordinary[MAXN],root[MAXN];
	bitset<MAXN> loop;
	void Topo(){
		loop.set();
		queue<int> q;
		for(int i = 1;i<=n;i++){
			if(rd[i]==0) q.push(i);
		}
		while(!q.empty()){
			int k = q.front();q.pop();
			loop.reset(k);
			if(--rd[nxt[k]]==0) q.push(nxt[k]);
		}
	}
	//ST
	int ST_fath[MAXN][LOGN],dis[MAXN],is[MAXN];
	int jump(int x,int tmp){
		int k = 0;
		while(tmp){
			if(tmp&1) x = ST_fath[x][k];
			tmp>>=1;
			k++;
		}
		return x;
	}
	void ST_init(){
		for(int j = 1;j<LOGN;j++){
			for(int i = 1;i<=n;i++){
				ST_fath[i][j] = ST_fath[ST_fath[i][j-1]][j-1];
			}
		}
	}
	//Base ring tree
	int find_loop(int k,int &r){
		if(dis[k]) return r=root[k],dis[k];
		if(loop[k]) return r=k,dis[k]=0;
		ST_fath[k][0] = nxt[k];
		return dis[k] = find_loop(nxt[k],root[k])+1,r=root[k],dis[k];
	}
	vector<int> has[MAXN];
	bitset<MAXN> vis;
	void dfs(int k){
		if(vis[k]) return;
		vis[k] = 1;
		is[k] = has[get_father(k)].size();
		has[get_father(k)].push_back(k);
		dfs(nxt[k]);
		
	}
	signed main(){
		read(n);read(k);
		for(int i = 1;i<=n;i++) fath[i] = i;
		for(int i = 1;i<=n;i++){
			read(nxt[i]);
			fath[get_father(i)] = get_father(nxt[i]);
			rd[nxt[i]]++;
		}
		for(int i = 1;i<=n;i++){
			read(ordinary[i]);
		}
		Topo();
		for(int i = 1;i<=n;i++){
			find_loop(i,root[i]);
		}
		for(int i = 1;i<=n;i++){
			if(loop[i]){
				dfs(i);
			}
		}
		ST_init();
		for(int i = 1;i<=n;i++){
			if(k<dis[i]) write(ordinary[jump(i,k)],' ');
			else write(ordinary[has[get_father(root[i])][(is[root[i]]+(k-dis[i]))%has[get_father(root[i])].size()]],' ');
		}
		return 0;
	}
}
signed main(){
//	freopen(".in","r",stdin);
//	freopen(".out","w",stdout);
//	ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);
	int T = 1;
//	gtx::read(T);
	while(T--) gtx::main();
	return 0;
}

Tag

AtcoderABC
基环树

标签:tmp,int,题解,void,ABC367E,read,abc367,Permute
From: https://www.cnblogs.com/gutongxing/p/18365379

相关文章

  • 对树链剖分的爱 题解
    前言题目链接:洛谷。题意简述给出一棵\(n\)个节点以\(1\)为根的有根树。对于第\(2\leqi\leqn\)个节点,其父亲\(f_i\)在\([l_i,r_i]\)中均匀随机。每个树的边有边权,初始为\(0\)。现在有\(m\)次操作,第\(i\)次操作表示将\((u_i,v_i)\)的路径上所有的边的权值统......
  • AtCoder Beginner Contest 367 题解(E~G)
    E转换关系看作有向边,\(n\)点\(n\)边构成基环树森林,基环树森林k后继唯一,记f[i][j]为点\(i\)的\(2^j\)级祖先,随便倍增。F一眼哈希,不知道有没有不哈希的做法。在这里我们不关心元素的顺序,只关心元素是否出现以及出现几次,考虑一个\(n\)位\(n+1\)进制数,\(a_i\)出现一......
  • [题解]CF76B Mice
    思路比较简单的贪心。对于可以选择两个奶酪的老鼠,我们先将它们忽略掉。现在所有老鼠所吃的奶酪是唯一确定的。考虑加上可以选择两个奶酪的老鼠如何选择。显然,如果它可以选择一个没有任何老鼠吃过的奶酪,它必然这样选择。其次,如果它可以选择的奶酪被吃掉的时间\(t\)与它到达奶......
  • ABC 367 题解
    AtCoderBeginnerContest367题解:\(Problem\hspace{2mm}A-Shout\hspace{2mm}Everyday\)题目链接opinion:~~code:#include<bits/stdc++.h>#definelllonglong#definepiipair<int,int>usingnamespacestd;lla,b,c;intmain(){ i......
  • abc364 题解
    第一次场切A~F,写个题解纪念一下。比赛链接:https://atcoder.jp/contests/abc367A-ShoutEveryday题意:高桥每天\(B\)时刻睡觉,\(C\)时刻起床(\(B,C\)时刻也在睡觉),请问高桥\(A\)时刻是否没睡。思路:对于\(B<=C\)和\(B>C\)分别处理即可。代码:https://atcoder.jp/con......
  • 题解:AtCoder Beginner Contest 367
    总体情况A题意在AtCoder王国,居民们每天都要在\(A\)点大声喊出他们对章鱼烧的热爱。住在AtCoder王国的高桥每天\(B\)点睡觉,\(C\)点起床(\(24\)小时钟)。他醒着的时候可以喊出对章鱼烧的爱,但睡着的时候却不能。判断他是否每天都能喊出对章鱼烧的爱。这里,一天有\(24......
  • P10886 【MX-S3-T2】「FeOI Round 1」Journey 题解
    我们肯定是要先求出来一个位置被加的次数,然后和权值乘一下就行。对于一个位置\(i\),右端点\(b\)肯定是随便选,一共\(n-i+1\)种情况。再是对于每一种步长\(c\),左端点\(a\)都有\(\left\lceil\dfrac{i}{c}\right\rceil\)种取值,暴力计算,时间复杂度\(O(n^2)\)。(提交记录)考虑......
  • P10888 【MX-S3-T4】「FeOI Round 1」醒餞の鳥 (feat. Feryquitous) 题解
    话说这题真的有紫吗(问号注意到数据范围中提到$\sum{nm}\le2\times10^5$,这里实际上是隐含了\(\min(n,m)\le\sqrt{2\times10^5}\)的。我们考虑根据\(n\)和\(m\)的大小关系设计出不同的算法。\(m<n\)一个比较直接的想法是对于每一个科目先按该科目的分数排序,这样......
  • 在相思树下 III 题解
    前言题目链接:洛谷。赛时脑子坨成一坨了,估计是T1的影响,写一篇题解来理清思路。题意简述给你一个长为\(n\)的序列\(a_{1\dotsn}\),你需要对它进行两种操作共\(n-1\)次。对一个长度为\(l\)的序列\(b_{1\dotsl}\)进行一次操作将会把序列变为一个长为\(l-1\)的序列......
  • n1gr tS0i 题解
    前言题目链接:洛谷。想了一个小时,想到后只用\(1\)分钟过了的题。官方题解过于晦涩,看到一篇很清晰的题解,于是写题解以记之。终于遇到时间瓶颈在输入的题目。题意简述有一个长度为\(n\)的\(\tt01\)串\(S\),你要对\(S\)进行恰好\(n\)次操作。每次操作选择\(1\leq......