[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;
}

浙公网安备 33010602011771号