hdu 5057(平方分割)

Argestes and Sequence

Time Limit: 5000/2500 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)


Problem Description
Argestes has a lot of hobbies and likes solving query problems especially. One day Argestes came up with such a problem. You are given a sequence a consisting of N nonnegative integers, a[1],a[2],...,a[n].Then there are M operation on the sequence.An operation can be one of the following:
S X Y: you should set the value of a[x] to y(in other words perform an assignment a[x]=y).
Q L R D P: among [L, R], L and R are the index of the sequence, how many numbers that the Dth digit of the numbers is P.
Note: The 1st digit of a number is the least significant digit.
 

Input
In the first line there is an integer T , indicates the number of test cases.
For each case, the first line contains two numbers N and M.The second line contains N integers, separated by space: a[1],a[2],...,a[n]—initial value of array elements.
Each of the next M lines begins with a character type.
If type==S,there will be two integers more in the line: X,Y.
If type==Q,there will be four integers more in the line: L R D P.

[Technical Specification]
1<=T<= 50
1<=N, M<=100000
0<=a[i]<= 231 - 1
1<=X<=N
0<=Y<= 231 - 1
1<=L<=R<=N
1<=D<=10
0<=P<=9
 

Output
For each operation Q, output a line contains the answer.
 

Sample Input
  
  
1 5 7 10 11 12 13 14 Q 1 5 2 1 Q 1 5 1 0 Q 1 5 1 1 Q 1 5 3 0 Q 1 5 3 1 S 1 100 Q 1 5 3 1
 

Sample Output
  
  
5 1 1 5 0 1
解题思路:首先很容易想到用线段树,但会超内存,所以只能换种思路了。这里参考了网上一种思路:平方分割,把数列进行分块操作,比较巧妙,平方分割详细的讲解参考《挑战程序设计竞赛》P183
#include <iostream>
#include <cmath>
using namespace std;

const int maxn = 1e5;
int arr[maxn], block[400][10][10];

int main() {
    int T;
    cin >> T;
    while (T--) {
        memset(block,0,sizeof(block));
        int N, M;
        cin >> N >> M;
        int size = sqrt(N * 1.0);
        for (int i = 0; i < N; ++i) {
            cin >> arr[i];
            for (int j = 0, t = arr[i]; j < 10; ++j, t /= 10) {
                block[i / size][j][t % 10] += 1;
            }
        }
        while (M--) {
            char op;
            cin >> op;
            if (op == 'S') {
                int x, y;
                cin >> x >> y;
                x -= 1;
                for (int i = 0, t = arr[x]; i < 10; ++i, t /= 10) {
                    block[x / size][i][t % 10] -= 1;
                }
                for (int i = 0, t = y; i < 10; ++i, t /= 10) {
                    block[x / size][i][t % 10] += 1;
                }
                arr[x] = y;
            }
            else {
                int l, r, d, p;
                cin >> l >> r >> d >> p;
                l -= 1, r -= 1, d -= 1;
                int res = 0;
                if (l / size == r / size) { //同一个块
                    for (int i = l; i <= r; ++i) {
                        for (int j = 0, t = arr[i]; j < 10; ++j, t /= 10) {
                            if (j == d && t % 10 == p) res += 1;
                        }
                    }
                    cout << res << endl;
                    continue;
                }
                for (int i = l; i < (l / size + 1) * size; ++i) {
                    for (int j = 0, t = arr[i]; j < 10; ++j, t /= 10) {
                        if (j == d && t % 10 == p) res += 1;
                    }
                }
                for (int i = l / size + 1; i < r / size; ++i) {
                    res += block[i][d][p];
                }
                for (int i = r / size * size; i <= r; ++i) {
                    for (int j = 0, t = arr[i]; j < 10; ++j, t /= 10) {
                        if (j == d && t % 10 == p) res += 1;
                    }
                }
                cout << res << endl;
            }
        }
    }
    return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值