题解:P11725 [JOIG 2025] 修学旅行 / School Trip
建树
我们可以将过程转化成一棵三叉树。
我们对样例进行建树(自下而上)。
让后建第二层。
最后确定根。
我们易知不进行任何事件时的答案为根。
我们就可以写出建树。
char build(int u,int d){
if(d==n){
w[cnt]=u;//第 cnt 个人的选择在树中的下标
return a[u].v=l[cnt++];
}
a[u].l=3*u;//左
a[u].mid=3*u+1;//中
a[u].r=3*u+2;//右
map<char,int> v;
v.clear();
v[build(3*u,d+1)]++;
v[build(3*u+1,d+1)]++;
v[build(3*u+2,d+1)]++;
if(v['A']>v['B'])return a[u].v='A';
else return a[u].v='B';
}
修改
利用上面的
我们先来计算一下样例
最后答案仍然是根节点。
修改的代码如下。
char qz(int u){
map<char,int> v;
v.clear();
v[a[3*u].v]++;
v[a[3*u+1].v]++;
v[a[3*u+2].v]++;
if(v['A']>v['B']){
a[u].v='A';
}else{
a[u].v='B';
}
if(u==1)return a[u].v;//如果为根,直接返回
return qz(u/3);
}
完整代码
#include<bits/stdc++.h>
#define int long long
#pragma GCC optsize(2)
using namespace std;
int n,Q;
string l;
struct WZOI{
int l,mid,r;
char v;
}a[10000005];
int cnt=1;
int w[10000005];
char build(int u,int d){
if(d==n){
w[cnt]=u;
return a[u].v=l[cnt++];
}
a[u].l=3*u;
a[u].mid=3*u+1;
a[u].r=3*u+2;
map<char,int> v;
v.clear();
v[build(3*u,d+1)]++;
v[build(3*u+1,d+1)]++;
v[build(3*u+2,d+1)]++;
if(v['A']>v['B'])return a[u].v='A';
else return a[u].v='B';
}
char qz(int u){
map<char,int> v;
v.clear();
v[a[3*u].v]++;
v[a[3*u+1].v]++;
v[a[3*u+2].v]++;
if(v['A']>v['B']){
a[u].v='A';
}else{
a[u].v='B';
}
if(u==1)return a[u].v;
return qz(u/3);
}
signed main(){
cin>>n>>Q>>l;
int n3=l.size();
l=' '+l;
build(1,0);
while(Q--){
int x;
cin>>x;
a[w[x]].v=(a[w[x]].v=='A'?'B':'A');
cout<<qz(w[x]/3)<<endl;
}
return 0;
}
时间复杂度
首先是建树,每个节点遍历
然后是修改,修改一共遍历
所以总复杂度