リンク:
https://codeforces.com/contest/1234/problem/D
質問の意味:
あなたは、この文字列の小文字のラテン文字とqクエリからなる文字列sを与えられています。
サブストリングのことを思い出してください[L、R]の文字列sは、SR列SLSL + 1 ...です。例えば、「codeforces」のサブストリングは、「コード」、「ための」「力」、「F」ではなく「コーダ」および「トップ」です。
クエリの2種類があります。
1つのPOS C(1≤pos≤| S |、cが小文字のラテン文字です):CとSPOS(セットSPOS:= C)を交換してください。
2 LR(1≤l≤r≤| S |):ストリングSに異なる文字の数を計算する[L、R]。
アイデア:
セグメントツリーのメンテナンスバイナリは、これまでの間隔で使用されるメンテナンス対応するアルファベットの各ビットは、間隔がそれにマージされます。
コード:
#include <bits/stdc++.h>
using namespace std;
const int MAXN = 1e5+10;
char s[MAXN];
int tree[MAXN*4];
int n, q;
void PushUp(int root)
{
tree[root] = tree[root<<1] | tree[root<<1|1];
}
void Build(int root, int l, int r)
{
if (l == r)
{
tree[root] = 1<<(s[l]-'a');
return;
}
int mid = (l+r)/2;
Build(root<<1, l, mid);
Build(root<<1|1, mid+1, r);
PushUp(root);
}
void Update(int root, int l, int r, int p, int c)
{
if (l == r)
{
tree[root] = 1<<c;
return;
}
int mid = (l+r)/2;
if (p <= mid)
Update(root<<1, l, mid, p, c);
else
Update(root<<1|1, mid+1, r, p, c);
PushUp(root);
}
int Query(int root, int l, int r, int ql, int qr)
{
if (qr < l || ql > r)
return 0;
if (ql <= l && r <= qr)
return tree[root];
int mid = (l+r)/2;
int res = 0;
res |= Query(root<<1, l, mid, ql, qr);
res |= Query(root<<1|1, mid+1, r, ql, qr);
return res;
}
int main()
{
scanf("%s", s+1);
n = strlen(s+1);
Build(1, 1, n);
scanf("%d", &q);
int op, l, r;
char val;
while (q--)
{
scanf("%d", &op);
if (op == 1)
{
scanf("%d %c", &l, &val);
Update(1, 1, n, l, val-'a');
}
else
{
scanf("%d %d", &l, &r);
int res = Query(1, 1, n, l, r);
int cnt = 0;
while (res)
{
if (res&1)
cnt++;
res >>= 1;
}
printf("%d\n", cnt);
}
}
return 0;
}