题目链接
https://codeforces.com/problemset/problem/1535/D
思路
容易发现,所有的比赛可以看成一棵满二叉树,因此我们可以使用线段树进行求解。
我们规定,对于线段树上的一个节点 u u u,其左子树代表编号更小的参赛选手,右子树代表编号更大的参赛选手。
如果 s [ u ] = 0 s[u]=0 s[u]=0,则线段树对应节点的 s u m sum sum值等于左子树的 s u m sum sum值。
如果 s [ u ] = 1 s[u]=1 s[u]=1,则线段树对应节点的 s u m sum sum值等于右子树的 s u m sum sum值。
如果 s [ u ] = 0 s[u]=0 s[u]=0,则线段树对应节点的 s u m sum sum值等于左子树的 s u m sum sum值与右子树的 s u m sum sum值的和。
对于每一次的单点修改,我们可以使用两个 m a p map map对线段树中的节点下标与字符串 s s s中的下标进行映射。
令 n = 2 k n = 2^k n=2k,则时间复杂度为: O ( n l o g 2 n + q × l o g 2 n ) O(nlog_{2}n+q \times log_{2}n) O(nlog2n+q×log2n)
代码
#include <bits/stdc++.h>
using namespace std;
#define int long long
const int N = 3e5 + 5;
int n, k, q;
char s[N];
map<int, int>mp;//线段树节点与比赛场次的映射
int qmi(int a, int b)
{
int res = 1;
while (b)
{
if (b & 1) res = res * a;
b >>= 1;
a = a * a;
}
return res;
}
struct segmenttree
{
struct node
{
int l, r, sum;
};
vector<node>tree;
segmenttree(): tree(1) {}
segmenttree(int n): tree(n * 4 + 1) {}
void pushup(int u)
{
auto &root = tree[u], &left = tree[u << 1], &right = tree[u << 1 | 1];
if (s[mp[u]] == '?')
{
root.sum = left.sum + right.sum;
}
if (s[mp[u]] == '0')
{
root.sum = left.sum;
}
if (s[mp[u]] == '1')
{
root.sum = right.sum;
}
}
void build(int u, int l, int r)
{
auto &root = tree[u];
root = {l, r};
if (l == r)
{
root.sum = 1;
}
else
{
int mid = l + r >> 1;
build(u << 1, l, mid);
build(u << 1 | 1, mid + 1, r);
pushup(u);
}
}
void modify(int u)
{
pushup(u);
if (u > 1)
{
modify(u >> 1);
}
}
};
void solve()
{
cin >> k;
n = qmi(2, k);
for (int i = 1; i < n; i++)
{
cin >> s[i];
}
map<int, int>st;//比赛场次与线段树节点的映射
for (int i = 1, r = n - 1, idx = 0; i <= k; i++)
{
int len = qmi(2, i - 1);
int l = r - len + 1;
for (int k = l; k <= r; k++)
{
idx++;
mp[idx] = k;
st[k] = idx;
}
r = l - 1;
}
segmenttree smt(n);
smt.build(1, 1, n);
cin >> q;
while (q--)
{
int p;
char c;
cin >> p >> c;
s[p] = c;
smt.modify(st[p]);
cout << smt.tree[1].sum << endl;
}
}
signed main()
{
ios::sync_with_stdio(false);
cin.tie(0), cout.tie(0);
int test = 1;
// cin >> test;
for (int i = 1; i <= test; i++)
{
solve();
}
return 0;
}