Codeforces 794F. Leha and security system 线段树

F. Leha and security system

Bankopolis, the city you already know, finally got a new bank opened! Unfortunately, its security system is not yet working fine... Meanwhile hacker Leha arrived in Bankopolis and decided to test the system!

Bank has n cells for clients‘ money. A sequence from n numbers a1, a2, ..., an describes the amount of money each client has. Leha wants to make requests to the database of the bank, finding out the total amount of money on some subsegments of the sequence and changing values of the sequence on some subsegments. Using a bug in the system, Leha can requests two types of queries to the database:

  • 1 l r x y denoting that Leha changes each digit x to digit y in each element of sequence ai, for which l ≤ i ≤ r is holds. For example, if we change in number 11984381 digit 8 to 4, we get 11944341. It‘s worth noting that Leha, in order to stay in the shadow, never changes digits in the database to 0, i.e. y ≠ 0.
  • 2 l r denoting that Leha asks to calculate and print the sum of such elements of sequence ai, for which l ≤ i ≤ r holds.

As Leha is a white-hat hacker, he don‘t want to test this vulnerability on a real database. You are to write a similar database for Leha to test.

Input

The first line of input contains two integers n and q (1 ≤ n ≤ 105, 1 ≤ q ≤ 105) denoting amount of cells in the bank and total amount of queries respectively.

The following line contains n integers a1, a2, ..., an (1 ≤ ai < 109) denoting the amount of money in each cell initially. These integers do not contain leading zeros.

Each of the following q lines has one of the formats:

  • 1 l r x y (1 ≤ l ≤ r ≤ n, 0 ≤ x ≤ 9, 1 ≤ y ≤ 9), denoting Leha asks to change each digit x on digit y for each element ai of the sequence for which l ≤ i ≤ r holds;
  • 2 l r (1 ≤ l ≤ r ≤ n), denoting you have to calculate and print the sum of elements ai for which l ≤ i ≤ r holds.

Output

For each second type query print a single number denoting the required sum.

Examples

input

5 538 43 4 12 701 1 3 4 82 2 41 4 5 0 81 2 5 8 72 1 5

output

103207

Note

Let‘s look at the example testcase.

Initially the sequence is [38, 43, 4, 12, 70].

After the first change each digit equal to 4 becomes 8 for each element with index in interval [1; 3]. Thus, the new sequence is [38, 83, 8, 12, 70].

The answer for the first sum‘s query is the sum in the interval [2; 4], which equal 83 + 8 + 12 = 103, so the answer to this query is 103.

The sequence becomes [38, 83, 8, 12, 78] after the second change and [38, 73, 7, 12, 77] after the third.

The answer for the second sum‘s query is 38 + 73 + 7 + 12 + 77 = 207.

题意:

  给你n个数

  操作1:l r x y,区间[l,r]内所有数,数位上为x的都转化为y

  操作2: l r 求区间和

题解:

  线段树区间合并

  建立10颗线段树,分别表示数字0~9所代表的值

  将x转化为y也就是在将第x颗线段树区间[l,r]和减去,加到第y颗线段树上

  这里的延时操作有点小技巧

  每次push_down的时候保持每个点(0~9)指向唯一的另外一个点,这样再更新的时候才不会超时

#include<bits/stdc++.h>
using namespace std;
#pragma comment(linker, "/STACK:102400000,102400000")
#define ls i<<1
#define rs ls | 1
#define mid ((ll+rr)>>1)
#define pii pair<int,int>
#define MP make_pair
typedef long long LL;
const long long INF = 1e18+1LL;
const double Pi = acos(-1.0);
const int N = 5e5+10, M = 1e3+20, mod = 1e9+7,inf = 2e9;

LL sum[N][11],H[N],a[N],sum2[12];
int lazy[N][11],vis[12];

void push_down(int i,int ll,int rr) {
    if(ll == rr) return ;

    for(int j = 0; j < 10; ++j) vis[j] = lazy[ls][j], sum2[j] = sum[ls][j];
    for(int j = 0; j < 10; ++j) {
        if(lazy[i][j] != j) {
            for(int k = 0; k < 10; ++k) {
                if(lazy[ls][k] == j) vis[k] = lazy[i][j];
            }
            sum2[lazy[i][j]] += sum[ls][j]; sum2[j] -= sum[ls][j];
        }
    }
    for(int j = 0; j < 10; ++j)
        lazy[ls][j] = vis[j], sum[ls][j] = sum2[j];

    for(int j = 0; j < 10; ++j) vis[j] = lazy[rs][j], sum2[j] = sum[rs][j];
    for(int j = 0; j < 10; ++j) {
        if(lazy[i][j] != j) {
            for(int k = 0; k < 10; ++k) {
                if(lazy[rs][k] == j) vis[k] = lazy[i][j];
            }sum2[lazy[i][j]] += sum[rs][j]; sum2[j] -= sum[rs][j];
        }
    }
    for(int j = 0; j < 10; ++j)
        lazy[rs][j] = vis[j], sum[rs][j] = sum2[j];

    for(int j = 0; j < 10; ++j) lazy[i][j] = j;
}

void push_up(int i,int ll,int rr) {
    for(int j = 0; j <= 9; ++j) {
        sum[i][j] = sum[ls][j] + sum[rs][j];
    }
}

void build(int i,int ll,int rr) {

    for(int j = 0; j < 10; ++j) lazy[i][j] = j;

    if(ll == rr) {
        for(int j = 0; j < 10; ++j) sum[i][j]  =0;
        LL tmp = a[ll];
        for(int j = 1; j <= 12; ++j) {
            sum[i][tmp%10] += H[j-1];
            tmp/=10;
            if(tmp == 0) break;
        }
        return ;
    }

    build(ls,ll,mid); build(rs,mid+1,rr);
    push_up(i,ll,rr);
}

void update(int i,int ll,int rr,int x,int y,int f,int s) {

    push_down(i,ll,rr);
    if(ll == x && rr == y) {
        for(int j = 0; j <= 9; ++j)
        if(lazy[i][j] == f) {
            lazy[i][j] = s;
            sum[i][s] += sum[i][f];
            sum[i][f] = 0;
        }
        return ;
    }
    if(y <= mid) update(ls,ll,mid,x,y,f,s);
    else if(x > mid) update(rs,mid+1,rr,x,y,f,s);
    else {

        update(ls,ll,mid,x,mid,f,s);
        update(rs,mid+1,rr,mid+1,y,f,s);

    }

    push_up(i,ll,rr);

}

LL query(int i,int ll,int rr,int x,int y) {
    push_down(i,ll,rr);
    if(ll == x && rr == y) {
        LL ret = 0;
        for(int j = 1; j <= 9; ++j) {
            ret += 1LL*j*sum[i][j];
        }
        return ret;
    }
    if(y <= mid) return query(ls,ll,mid,x,y);
    else if(x > mid) return query(rs,mid+1,rr,x,y);
    else {
        return query(ls,ll,mid,x,mid)+query(rs,mid+1,rr,mid+1,y);
    }
    push_up(i,ll,rr);

}

int n,q;

int main() {

    scanf("%d%d",&n,&q);

    for(int i = 1; i <= n; ++i) {
        scanf("%I64d",&a[i]);
    }

    H[0] = 1;
    for(int i = 1; i <= 13; ++i) H[i] = H[i-1]*10;

    build(1,1,n);

    for(int i = 1; i <= q; ++i) {
        int op,x,y,l,r;
        scanf("%d",&op);
        if(op == 1) {
            scanf("%d%d%d%d",&l,&r,&x,&y);
            if(x == y) continue;
            update(1,1,n,l,r,x,y);
        }
        else {
            scanf("%d%d",&l,&r);
            printf("%I64d\n",query(1,1,n,l,r));
        }
    }

    return 0;
}
时间: 2024-08-03 22:09:19

Codeforces 794F. Leha and security system 线段树的相关文章

codeforces 794F Leha and security system

目录 codeforces 794F Leha and security system 题意 题解 Code codeforces 794F Leha and security system 题目传送门 题意 给出一个长度为\(n\)的序列,有两种操作: 1.将区间\([l,r]\)中每一个元素的数字\(x\)改为\(y\). 2.询问区间\([l,r]\)的元素之和. 一共\(q\)次操作.\((1 \leq n,q \leq 10^5)\) 题解 看起来就很可做的题目,实际上只是线段树的应用

codeforces 444 C. DZY Loves Colors(线段树)

题目大意: 1 l r x操作 讲 [l,r]上的节点涂成x颜色,并且每个节点的值都加上 |y-x| y为涂之前的颜色 2 l r  操作,求出[l,r]上的和. 思路分析: 如果一个区间为相同的颜色.那么我们才可以合并操作. 所以我们之前找相同的区间就好. 但是问题是如何合并操作. 那么我们定义一个val  表示这个区间每个位置上应该加上的值. pushdown 的时候这个值是可以相加的. #include <cstdio> #include <iostream> #includ

codeforces 446C DZY Loves Fibonacci Numbers 线段树

假如F[1] = a, F[2] = B, F[n] = F[n - 1] + F[n - 2]. 写成矩阵表示形式可以很快发现F[n] = f[n - 1] * b + f[n - 2] * a. f[n] 是斐波那契数列 也就是我们如果知道一段区间的前两个数增加了多少,可以很快计算出这段区间的第k个数增加了多少 通过简单的公式叠加也能求和 F[n]  = f[n - 1] * b + f[n - 2] * a F[n - 1] = f[n - 2] * b + f[n - 3] * a ..

Codeforces 444C DZY Loves Colors 水线段树

题目链接:点击打开链接 水.. #include <cstdio> #include <cstring> #include <iostream> #include <algorithm> #include <math.h> #include <set> #include <vector> #include <map> using namespace std; #define ll long long #defi

CodeForces - 383C Propagating tree(dfs + 线段树)

题目大意: 给出一棵树,树上每个节点都有权值,然后有两个操作. 1 x val 在结点x上加上一个值val,x的儿子加上 -val,x的儿子的儿子加上 - (-val),以此类推. 2 x 问x节点的值. 思路分析: 每个节点上加值都是给自己的儿子节点加,而且这个是颗树. 比如样例上的,如果你给node 1加一个值,那么五个节点都加. 再给node 2加个值,2的儿子节点也加了,之前给1加的值也要加到2号节点的儿子. 所以你会发现节点的儿子会存在一个从属的关系. 这样的话,我们可以把所有节点从新

codeforces Beta Round #19 D. Point (线段树 + set)

题目大意: 对平面上的点进行操作. add x y 在 (x,y )上加一个点. remove x y 移除 (x,y)上的点. find x y 求出在(x,y)右上角离他最近的点,优先级是靠左,靠下. 思路分析: find 操作 比较麻烦. 要保证x大的同时还要确保x最小,而且该x上还要有点. 这样要找大的时候要小的,就是在线段树上选择性的进入左子树还是右子树. 所以核心就是,用set维护叶子节点. 然后查找的时候去叶子节点找,如果这个叶子节点有蛮子的 x y  就输出,否则回溯去另外一个子

Nastya Hasn&#39;t Written a Legend(Codeforces Round #546 (Div. 2)E+线段树)

题目链接 传送门 题面 题意 给你一个\(a\)数组和一个\(k\)数组,进行\(q\)次操作,操作分为两种: 将\(a_i\)增加\(x\),此时如果\(a_{i+1}<a_i+k_i\),那么就将\(a_{i+1}\)变成\(a_i+k_i\),如果\(a_{i+2}<a_i+k_i\),则将\(a_{i+2}\)变成\(a_{i+1}+k_{i+1}\),以此类推. 查询\(\sum\limits_{i=l}^{r}a_i\). 思路 我们首先存下\(k\)数组的前缀和\(sum1\),

Codeforces Gym 100513F F. Ilya Muromets 线段树

F. Ilya Muromets Time Limit: 20 Sec Memory Limit: 256 MB 题目连接 http://codeforces.com/gym/100513/problem/F Description I Ilya Muromets is a legendary bogatyr. Right now he is struggling against Zmej Gorynych, a dragon with n heads numbered from 1 to nf

codeforces 573B B. Bear and Blocks(线段树+dp)

题目链接: codeforces 573B 题目大意: 给出n个连续塔,每个塔有高度hi,每次取走最外层的块,问需要多少次操作能够拿光所有的块. 题目分析: 首先我们可以知道第一次操作时,对于每个塔的变化满足如下的公式: hi=min(hi?1,hi?1,hi+1) 每次操作都满足如下的递推式,我们递推一下得到第k次操作第i的塔的高度: hi=max(0,minj=0i{min(hi?j?(k?j),hi+j?(k?j)}?hi=max(0,minj=0i{min(hi?j+j?k,hi+j+j