[AGC044C] Strange Dance

Trie 树原来不一定要从高位往低位建啊。


长度为 \(3^n\) 的序列 \(P\),下标从 \(0\) 开始,满足 \(p_i = i\)

你需要按顺序进行 \(q\) 次变换,每次变换具有以下两种形式之一:

  • 对于所有 \(i\),将 \(p_i\) 三进制位中的 \(1\)\(2\) 反转。

  • 对于所有 \(i\),将 \(p_i\)\(1\) 后对 \(3^n\) 取模。

\(q\) 次变换后的序列 \(P\)

\(1 \leq n \leq 12\)\(1 \leq q \leq 2 \times 10^5\)


考虑模拟变换的过程。

我们考虑建立 Trie 树,接下来通过修改 Trie 树的方法修改序列。

对于第一种操作,我们考虑对于每个节点交换 \(1\) 子树和 \(2\) 子树。

显然暴力修改涉及的节点过多,考虑打标记。

接下来考虑第二种操作,此时需要引进我们的核心 trick,即从低位往高位建立 Trie 树。

从低位往高位建立 Trie 树之后,根节点的 \(0\) 子树,\(1\) 子树和 \(2\) 子树要循环移动。

我们发现,对于 \(0\)\(1\),变成 \(1\)\(2\) 后不会进位,然而 \(2\) 变成 \(0\) 会进位。

你发现这等价于在新的 \(0\) 子树上进行同样的加 \(1\) 操作,递归下去即可。

时间复杂度 \(O(3^n+nq)\)

#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
int Trie[1000010][3],pow_3[20],node_tot;
bool lazy[1000010];
int ans[1000010];
void change1(int id){
	int son0=Trie[id][0];
	int son1=Trie[id][1];
	int son2=Trie[id][2];
	bool lazy0=lazy[Trie[id][0]];
	bool lazy1=lazy[Trie[id][1]];
	bool lazy2=lazy[Trie[id][2]];
	Trie[id][0]=son0;
	Trie[id][1]=son2;
	Trie[id][2]=son1;
	lazy[Trie[id][0]]=lazy0;
	lazy[Trie[id][1]]=lazy2;
	lazy[Trie[id][2]]=lazy1;
}
void change2(int id){
	int son0=Trie[id][0];
	int son1=Trie[id][1];
	int son2=Trie[id][2];
	bool lazy0=lazy[Trie[id][0]];
	bool lazy1=lazy[Trie[id][1]];
	bool lazy2=lazy[Trie[id][2]];
	Trie[id][0]=son2;
	Trie[id][1]=son0;
	Trie[id][2]=son1;
	lazy[Trie[id][0]]=lazy2;
	lazy[Trie[id][1]]=lazy0;
	lazy[Trie[id][2]]=lazy1;
}
void pushdown(int id){
	if(lazy[id]){
		lazy[id]=!lazy[id];
		int son0=Trie[id][0],son1=Trie[id][1],son2=Trie[id][2];
		change1(son0);
		change1(son1);
		change1(son2);
		lazy[son0]=!lazy[son0];
		lazy[son1]=!lazy[son1];
		lazy[son2]=!lazy[son2];
	}
}
void modify(int id){
	pushdown(id);
	change2(id);
	if(Trie[id][0]){
		modify(Trie[id][0]);
	}
}
int output[1000010];
void dfs(int id,int pre,int dep){
	if(ans[id]!=-1){
		output[ans[id]]=pre;
	}
	pushdown(id);
	if(Trie[id][0]){
		dfs(Trie[id][0],pre+0*pow_3[dep],dep+1);
	}
	if(Trie[id][1]){
		dfs(Trie[id][1],pre+1*pow_3[dep],dep+1);
	}
	if(Trie[id][2]){
		dfs(Trie[id][2],pre+2*pow_3[dep],dep+1);
	}
}
int main(){
	int n;
	scanf("%d",&n);
	pow_3[0]=1;
	for(int i=1;i<=n;i++){
		pow_3[i]=pow_3[i-1]*3;
	}
	node_tot++;
	memset(ans,-1,sizeof(ans));
	for(int i=0;i<pow_3[n];i++){
		int pre=1;
		for(int j=0;j<n;j++){
			int cmd=i/pow_3[j]%3;
			if(!Trie[pre][cmd]){
				Trie[pre][cmd]=++node_tot;
			}
			pre=Trie[pre][cmd];
		}
		ans[pre]=i;
	}
	char ch;
	while(cin>>ch){
		if(ch=='S'){
			lazy[1]=!lazy[1];
			change1(1);
		}
		else{
			modify(1);
		}
	}
	dfs(1,0,0);
	for(int i=0;i<pow_3[n];i++){
		printf("%d ",output[i]); 
	}
	return 0; 
}
posted @ 2026-01-15 21:15  Oken喵~  阅读(4)  评论(0)    收藏  举报