1791F. Range Update Point Query Codeforces Round #849 (Div. 4)

题目链接Problem - 1791F - Codeforces点击以获得更佳的阅读体验

F. Range Update Point Query

time limit per test2 seconds

memory limit per test256 megabytes

inputstandard input

outputstandard output

Given an array a1,a2,…,an�1,�2,…,��, you need to handle a total of q updates and queries of two types:

  • 11 l r — for each index i with l≤i≤r�≤�≤�, update the value of ai�� to the sum of the digits of ai��.

  • 22 x — output ax��.

Input

The first line of the input contains an integer t (1≤t≤10001≤�≤1000) — the number of testcases.

The first line of each test case contains two integers n and q (1≤n,q≤2⋅1051≤�,�≤2⋅105) — the size of the array and the number of queries, respectively.

The second line of each test case contains n integers a1,a2,…,an�1,�2,…,�� (1≤ai≤1091≤��≤109).

The next q lines of each test case are of two forms:

  • 11 l r (1≤l≤r≤n1≤�≤�≤�) — it means, for each index i with l≤i≤r�≤�≤�, you should update the value of ai�� to the sum of its digits.

  • 22 x (1≤x≤n1≤�≤�) — it means you should output ax��.

There is at least one query of the second type.

The sum of n over all test cases does not exceed 2⋅1052⋅105.

The sum of q over all test cases does not exceed 2⋅1052⋅105.

Output

For each test case, output the answers of queries of the second type, in the order they are given.

Example

input

Copy

35 81 420 69 1434 20231 2 32 22 32 41 2 52 12 32 52 39999 10001 1 22 12 21 112 1

output

Copy

6

15

1434

1

6

7

36

1

1

Note

In the first test case, the following process occurs:

  • Initially, a=[1,420,69,1434,2023]�=[1,420,69,1434,2023].

  • The operation is performed for l=2�=2, r=3�=3, yielding [1,6,15,1434,2023][1,6,15,1434,2023].

  • We are queried for x=2�=2, x=3�=3, and x=4�=4, and output 66, 1515, and 14341434.

  • The operation is performed for l=2�=2, r=5�=5, yielding [1,6,6,12,7][1,6,6,12,7].

  • We are queried for x=1�=1, x=3�=3, and x=5�=5, and output 11, 66, and 77.

题意是有两个操作,

1操作是给出一个区间l到r,这个区间的每个数都变成它们各个数位上的树之和,如420就会变成6

2 操作是输出该下标的数的值。

树状数组做法

本题有两种做法,一种是用树状数组平推,这种做法基本不需要动脑子,只要记得树状数组的几种应用情况就行,唯一需要动脑子的地方就是要考虑清楚树状数组中存的是什么,以及区间修改时需要使用差分树状数组。

以下是树状数组单点修改的理解,理解这个其实基本上就理解了树状数组。

1(001) C[1]+=A[1]

lowbit(1)=001 1+lowbit(1)=2(010) C[2]+=A[1]

lowbit(2)=010 2+lowbit(2)=4(100) C[4]+=A[1]

lowbit(4)=100 4+lowbit(4)=8(1000) C[8]+=A[1]

————————————————

版权声明:本文为CSDN博主「bestsort」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。

原文链接:https://blog.csdn.net/bestsort/article/details/80796531

关于更多的树状数组可以看看上面的博客链接,讲的很好,如果对lowbit操作不清楚也可以看上面的博客。

code:


#include<iostream>
#include<algorithm>
#include<queue>
#include<string>
#include<vector>
#include<cstring>
#include<map>
#include<set>
using namespace std;
const int manx = 2e5 + 10;
typedef long long ll;
int cnt[manx];
int lowbit(int x)
{
    return x & -x;
}
int check(int x)
{
    int k = 0;
    while (x)
    {
        k += x % 10;
        x = x / 10;
    }
    return k;
}
int a[manx];
void update(int c, int n, int k)
{
    for (int i = c; i <= n; i+=lowbit(i))
    {
        cnt[i] += k;
    }
}
int getsum(int c)
{
    ll sum = 0;
    for (int i = c; i; i -= lowbit(i))
    {
        sum += cnt[i];
    }
    return sum;
}//求前缀和是为了知道在该位置进行了几次操作1
void solve()
{
    int n,q;
    cin >> n>>q;
    for (int i = 1; i <= n; i++)
    {
        cin >> a[i];
        cnt[i] = 0;
    }
    while (q--)
    {
        int x;
        cin >> x;
        if (x == 1)
        {
            int l, r;
            cin >> l >> r;
            update(l, n, 1);
            update(r + 1, n, -1);//更新差分数组,这里差分的数组的目的是为了求前缀和时,每个下标的操作1的个数啊,这样就可以准确的算出在该位置进行了几次操作1
        }
        else
        {
            int c;
            cin >> c;
            ll ans = a[c];
            for (int i = 1; i <= getsum(c); i++)
            {
                ans = check(ans);
                if (ans < 10)break;
            }
            cout << ans << endl;
        }
    }
}
int main()
{
    int t;
    cin >> t;
    //t = 1;
    while (t--)
    {
        solve();
    }
}

集合set的巧妙做法。

集合set做法是发现,当1操作的数小于10时,这个数的值就不会再变了,那么可以把所有大于10数的下标都放入集合set中,如果这个数操作后小于10了,那么就把这个数的下边从set里弹出。


#include<iostream>
#include<algorithm>
#include<queue>
#include<string>
#include<vector>
#include<cstring>
#include<map>
#include<set>
using namespace std;
const int manx = 2e5 + 10;
typedef long long ll;
int cnt[manx];
int lowbit(int x)
{
    return x & -x;
}
int check(int x)
{
    int k = 0;
    while (x)
    {
        k += x % 10;
        x = x / 10;
    }
    return k;
}
int a[manx];
void update(int c, int n, int k)
{
    for (int i = c; i <= n; i+=lowbit(i))
    {
        cnt[i] += k;
    }
}
int getsum(int c)
{
    ll sum = 0;
    for (int i = c; i; i -= lowbit(i))
    {
        sum += cnt[i];
    }
    return sum;
}//求前缀和是为了知道在该位置进行了几次操作1
void solve()
{
    int n,q;
    cin >> n>>q;
    set<int>s;
    s.insert(n+1);
    for (int i = 1; i <= n; i++)
    {
        cin >> a[i];
        if (a[i] != check(a[i]))
        {
            s.insert(i);
        }
    }
    while (q--)
    {
        int x;
        cin >> x;
        if (x == 1)
        {
            int l, r;
            cin >> l >> r;
            while (n)
            {
                auto pot = *s.lower_bound(l);
                if (pot > r)
                {
                    break;
                }
                a[pot] = check(a[pot]);
                if (a[pot] == check(a[pot]))
                {
                    s.erase(pot);
                }
                l = pot + 1;
            }
        }
        else
        {
            int pot;
            cin >> pot;
            cout << a[pot] << endl;
        }
    }
}
int main()
{
    int t;
    cin >> t;
    //t = 1;
    while (t--)
    {
        solve();
    }
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值