[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喵~  阅读(21)  评论(0)    收藏  举报