題解:AT_abc367_e [ABC367E] Permute K times

辜铜星發表於2024-08-18

題意

給你一個長度為 \(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
基環樹

相關文章