Distinct Characters Queries 线段树+桶

You are given a string s consisting of lowercase Latin letters and q

queries for this string.

Recall that the substring s[l;r]
of the string s is the string slsl+1…sr

. For example, the substrings of "codeforces" are "code", "force", "f", "for", but not "coder" and "top".

There are two types of queries:

    1 pos c

(1≤pos≤|s|, c is lowercase Latin letter): replace spos with c (set spos:=c
);
2 l r
(1≤l≤r≤|s|): calculate the number of distinct characters in the substring s[l;r]

        .

Input

    The first line of the input contains one string s
consisting of no more than 105

lowercase Latin letters.

The second line of the input contains one integer q
(1≤q≤105

) — the number of queries.

The next q

    lines contain queries, one per line. Each query is given in the format described in the problem statement. It is guaranteed that there is at least one query of the second type.
Output

    For each query of the second type print the answer for it — the number of distinct characters in the required substring in this query.
Examples
Input
abacaba
5
2 1 4
1 4 b
1 5 b
2 4 6
2 1 7

Output
3
1
2

Input
dfcbbcfeeedbaea
15
1 6 e
1 4 b
2 6 14
1 7 b
1 12 c
2 6 8
2 1 6
1 7 c
1 2 f
1 10 a
2 7 9
1 10 a
1 14 b
1 1 f
2 1 11

Output
5
2
5
2
6

解释一下题目大概意思,就是给你一个小写英文字符串,然后有q次操作,每次操作先输入一个a,a可能为1或2

  • a=1:再输入一个值y和一个字符z,将原字符串y位置的字符替换为z

  • a=2:再输入两个值y,w,求出区间[y,w]有多少种英文字符


这题我先想到的是用线段树,但是也没有马上想出具体思路,可是有群友八分钟就用set一血了。。。最后我加上debug花了一个半小时T T。


来看这两种操作,很容易联想到线段树的区间查询和单点修改,所以我给每个线段树结点 开了26个桶,表示这个结点区间的某字符总共有多少个,更新和查询也需要稍加变换。

//https://blog.csdn.net/hesorchen
#include <stdio.h>
#include <iostream>
#include <algorithm>
#include <cmath>
#include <cstring>
#include <string>
#include <queue>
#include <stack>
#include <map>
#include <set>
using namespace std;
#define ll long long
#define endl "\n"
#define INF 0x3f3f3f3f
#define mod 1000000007
#define MAX 100010
struct node
{
    int k, l, r, sum, t[30];
} tr[4 * MAX];
string a;
void update(int k)
{
    for (int i = 1; i <= 26; i++)
        tr[k].t[i] = tr[k * 2].t[i] + tr[k * 2 + 1].t[i];
}
void build(int k, int l, int r)
{
    tr[k].l = l;
    tr[k].r = r;
    if (l == r)
    {
        tr[k].t[a[l] - 'a' + 1] = 1;
        return;
    }
    int mid = (l + r) >> 1;
    build(2 * k, l, mid);
    build(2 * k + 1, mid + 1, r);
    update(k);
}
int tong[35];
void change(int k, int x, char c1, char c2)
{
    if (tr[k].l == tr[k].r)
    {
        tr[k].t[c1 - 'a' + 1] = 0;
        tr[k].t[c2 - 'a' + 1] = 1;
        return;
    }
    int mid = (tr[k].l + tr[k].r) >> 1;
    if (x <= mid)
        change(2 * k, x, c1, c2);
    else
        change(2 * k + 1, x, c1, c2);
    update(k);
}
int query(int k, int l, int r)
{
    if (tr[k].l == l && tr[k].r == r)
    {
        int res = 0;
        for (int i = 1; i <= 26; i++)
            if (tr[k].t[i])
                tong[i] = 1;
        return res;
    }
    int mid = (tr[k].l + tr[k].r) >> 1;
    if (r <= mid)
        return query(k * 2, l, r);
    else if (l > mid)
        return query(k * 2 + 1, l, r);
    else
        return query(k * 2, l, mid) + query(k * 2 + 1, mid + 1, r);
}
int main()
{
    int n;
    cin >> a >> n;
    int len = a.size();
    a = " " + a;
    build(1, 1, len);
    while (n--)
    {
        int x, y, z;
        string w;
        cin >> x;
        if (x == 1)
        {
            cin >> y >> w;
            change(1, y, a[y], w[0]);
            a[y] = w[0];
        }
        else if (x == 2)
        {
            cin >> y >> z;
            fill(tong, tong + 32, 0);
            query(1, y, z);
            int ans = 0;
            for (int i = 1; i <= 30; i++)
                if (tong[i])
                    ans++;
            cout << ans << endl;
        }
    }
    return 0;
}
发布了76 篇原创文章 · 获赞 64 · 访问量 9331

猜你喜欢

转载自blog.csdn.net/hesorchen/article/details/104559367