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;
}
  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

hesorchen

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值