Codeforces Round #590 (Div. 3) D. Distinct Characters Queries(线段树, 位运算)

链接:

https://codeforces.com/contest/1234/problem/D

题意:

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].

思路:

线段树维护二进制,二进制的每一位维护对应的字母在区间是否使用过, 合并区间就是与一下.

代码:

#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;
}

原文地址:https://www.cnblogs.com/YDDDD/p/11618889.html

时间: 2024-10-12 09:17:22

Codeforces Round #590 (Div. 3) D. Distinct Characters Queries(线段树, 位运算)的相关文章

Codeforces Round #149 (Div. 2) E. XOR on Segment (线段树成段更新+二进制)

题目链接:http://codeforces.com/problemset/problem/242/E 给你n个数,m个操作,操作1是查询l到r之间的和,操作2是将l到r之间的每个数xor与x. 这题是线段树成段更新,但是不能直接更新,不然只能一个数一个数更新.这样只能把每个数存到一个数组中,长度大概是20吧,然后模拟二进制的位操作.仔细一点就行了. 1 #include <iostream> 2 #include <cstdio> 3 #include <cmath>

Codeforces Round #207 (Div. 1) A. Knight Tournament (线段树离线)

题目:http://codeforces.com/problemset/problem/356/A 题意:首先给你n,m,代表有n个人还有m次描述,下面m行,每行l,r,x,代表l到r这个区间都被x所击败了(l<=x<=r),被击败的人立马退出游戏让你最后输出每个人是被谁击败的,最后那个胜利者没被 人击败就输出0 思路:他的每次修改的是一个区间的被击败的人,他而且只会记录第一次那个被击败的人,用线段树堕落标记的话他会记录最后一次的,所以我们倒着来修改, 然后因为那个区间里面还包含了自己,在线段

Codeforces Round #310 (Div. 1) C. Case of Chocolate (线段树)

题目地址:传送门 这题虽然是DIV1的C..但是挺简单的..只要用线段树分别维护一下横着和竖着的值就可以了,先离散化再维护.每次查找最大的最小值<=tmp的点,可以直接在线段树里搜,也可以二分去找. 代码如下: #include <iostream> #include <string.h> #include <math.h> #include <queue> #include <algorithm> #include <stdlib.

Codeforces Round #225 (Div. 2)---E. Propagating tree(时间戳+线段树)

Iahub likes trees very much. Recently he discovered an interesting tree named propagating tree. The tree consists of n nodes numbered from 1 to n, each node i having an initial value ai. The root of the tree is node 1. This tree has a special propert

Codeforces Round #337 (Div. 2) D. Vika and Segments 线段树 矩阵面积并

D. Vika and Segments Vika has an infinite sheet of squared paper. Initially all squares are white. She introduced a two-dimensional coordinate system on this sheet and drew n black horizontal and vertical segments parallel to the coordinate axes. All

Codeforces Round #590 (Div. 3) Editorial

Codeforces Round #590 (Div. 3) Editorial 题目链接 官方题解 不要因为走得太远,就忘记为什么出发! Problem A 题目大意:商店有n件商品,每件商品有不同的价格,找出一个最小的可能值price,使得price * n >= sum,sum指的是原来商品价格的总和. 知识点:模拟 思路:求出sum/n向上取整即可,有两种方法.一是使用ceil()函数,但注意ceil()返回的是向上取整后的浮点数,所以要进行强制类型转换:二是直接向下取整,然后用if语句

递推 Codeforces Round #186 (Div. 2) B. Ilya and Queries

题目传送门 1 /* 2 递推:用cnt记录前缀值,查询区间时,两个区间相减 3 */ 4 #include <cstdio> 5 #include <algorithm> 6 #include <cmath> 7 #include <cstring> 8 using namespace std; 9 10 const int MAXN = 1e5 + 10; 11 const int INF = 0x3f3f3f3f; 12 char s[MAXN]; 1

Codeforces Round #216 (Div. 2) E. Valera and Queries (BIT)

题目大意: 给出很多条分布在 x 轴上的线段. 然后给出很多点集,问这些点集分布在多少条不同的线段上. 思路分析: 把点集分散成若干条线段. 如果点集做出的线段包含了某一条给出的线段的话,也就是说这个点集上不会有点在这条线段上. 所以我们就是求出 点集做出的线段包含了多少个给出的线段就可以了. 那么也就是比较l r的大小,排序之后用BIT #include <cstdio> #include <iostream> #include <algorithm> #includ

Codeforces Round #590 (Div. 3)

D. Distinct Characters Queries Description You are given a string ss consisting of lowercase Latin letters and qq queries for this string. Recall that the substring s[l;r]s[l;r] of the string ss is the string slsl+1…srslsl+1…sr. For example, the subs