CodeForces 103D 分块处理

题目链接:http://codeforces.com/problemset/problem/103/D

题意:给定一个长度为n的序列。然后q个询问。每个询问为(a,b),表示从序列第a项开始每b项的加和。

思路:2014集训队论文中的<<根号算法——不只是分块>>中提到这题。 传统的数据结构比较擅长处理连续区间的询问。但是不擅长处理间隔位置的询问。考虑到分块。 对于b>sqrt(n)的询问。我们暴力计算。可以发现b越大我们扫描的位置就会越小。最大扫描次数为O(n/sqrt(n))。然后对于b<sqrt(n)的。我们离线处理。以b为关键字来分组。 询问中b相同的为一组。 然后用预存部分和来计算。 这样整体的时间复杂度为O(n*sqrt(n)).

#define _CRT_SECURE_NO_DEPRECATE
#include<stdio.h>
#include<string.h>
#include<cstring>
#include<algorithm>
#include<queue>
#include<math.h>
#include<time.h>
#include<vector>
#include<iostream>
#include<map>
using namespace std;
typedef long long int LL;
const int MAXN = 3*100000 + 10;
int block, n, q, a[MAXN];
LL ans[MAXN],sum[MAXN];
struct Query{ int id, pos; Query(int _id = 0, int _pos = 0) :id(_id), pos(_pos){} };
vector<Query>D[MAXN];
void init(){
    block = (int)sqrt(n + 0.5);
    for (int i = 1; i < MAXN; i++){
        if (D[i].empty()){ continue; }
        if (i > block){
            for (int j = 0; j < D[i].size(); j++){
                LL res = 0;
                for (int k = D[i][j].pos; k <= n; k += i){
                    res += a[k];
                }
                ans[D[i][j].id] = res;
            }
        }
        else{
            memset(sum, 0, sizeof(sum));
            for (int j = n; j > 0; j--){
                sum[j] = a[j]+(j+i<=n?sum[i+j]:0);
            }
            for (int j = 0; j < D[i].size(); j++){
                ans[D[i][j].id] = sum[D[i][j].pos];
            }
        }
        D[i].clear();
    }
}
int main(){
//#ifdef kirito
//    freopen("in.txt", "r", stdin);
//    freopen("out.txt", "w", stdout);
//#endif
//    int start = clock();
    while (~scanf("%d", &n)){
        for (int i = 1; i <= n; i++){
            scanf("%d", &a[i]);
        }
        scanf("%d", &q);
        for (int i = 1; i <= q; i++){
            int pos, d;  scanf("%d%d", &pos, &d);
            D[d].push_back(Query(i, pos)); //相同d的为一组
        }
        init();
        for (int i = 1; i <= q; i++){
            printf("%lld\n", ans[i]);
        }
    }
//#ifdef LOCAL_TIME
//    cout << "[Finished in " << clock() - start << " ms]" << endl;
//#endif
    return 0;
}
时间: 2024-10-03 04:35:14

CodeForces 103D 分块处理的相关文章

(分块暴力)Time to Raid Cowavans CodeForces - 103D

题意 给你一段长度为n(1 ≤ n ≤ 3·1e5)的序列,m (1 ≤ p ≤ 3·1e5)个询问,每次询问a,a+b,a+2b+...<=n的和 思路 一开始一直想也想不到怎么分,去维护哪些信息,看了题解才知道 其实分块不仅仅可以将一列序列分块,还可以将数据进行分块,下面讨论具体做法 首先这道题不是在线询问,可以离线做,先读入所有的询问,将询问从小到大排序①当b<√n时,对于每一个b我们可以预处理出这样的一个数组sum[i],就是以i为起点间隔为b的序列和(可以用一个简单的dp求出来),然

CodeForces 455D 分块

题目链接:http://codeforces.com/problemset/problem/455/D 题意:给定一个长度为n的序列a[]. m次操作.共有两种操作 1 l r:将序列的a[l].a[l+1]...a[r]变成a[r].a[l].a[l+1]...a[r-1]:2 l r k:求序列a[l].a[l+1]...a[r]中有多少个值为k. 输入的l,r,k都是加密过的.所以要解密一下.规则为 l=(l+ans-1)%n+1  r=(r+ans-1)%n+1 k=(k+ans-1)%

CodeForces 444C 分块

题目链接:http://codeforces.com/problemset/problem/444/C 题意:给定一个长度为n的序列a[].起初a[i]=i,然后还有一个色度的序列b[],起初b[i]=0.现在有2种操作: 1 l r x:区间染色,a[l],a[l+1]...a[r]变成x.同时b[l],b[l+1]...b[r]加上对应的|x-a[i]|值. 2 l r:统计区间和,统计区间b[l],b[l+1]...b[r]的和. 思路:线段树是比较常见的做法.考虑分块.每块维护一个laz

CodeForces 551E 分块

题目链接:http://codeforces.com/problemset/problem/551/E 题意:给定一个长度为N的序列. 有2个操作 1 l r v:序列第l项到第r项加v(区间加),  2 v:求整个序列中值为v的数的位置的差值最大是多少.不存在输出-1. 思路:分块. 每块维护该块序列排序后的序列. 对于区间修改,我们定义一个lazy标记.对于整块的修改我们只修改lazy, 其他情况暴力修改.然后情况该块后重新加入修改后的块然后排序. 对于查询操作.查询每块时v应该减去该块的l

CodeForces 13E 分块

题目链接:http://codeforces.com/problemset/problem/13/E 题意:给定n个弹簧和每个弹簧初始的弹力a[].当球落在第i个位置.则球会被弹到i+a[i]的位置. 现在有2种操作: 1 a b:把第a个弹簧的弹力修改为b. 2 a:当球初始放入的位置为a时,需要弹几次才会弹出n.弹出前的最后一个位置是多少. 输出位置和次数. 思路:和BZOJ 2002一样. 然后记录一个最后弹出去的位置preidx.每次弹出当前块的时候记录当前的位置即可.然后最后再暴力模拟

codeforces 551E. GukiZ and GukiZiana 分块

题目链接 给出n个数, m个操作, 每个操作有两种, 将一段区间加上某个值, 或者询问一个k, a[i] = a[j] = k, 输出满足条件的最大的j-i, 如果没有输出-1. 做法是将数组分块, 第一次做这种, 抄的codeforces上面的代码... #include<bits/stdc++.h> using namespace std; #define pb(x) push_back(x) #define ll long long #define mk(x, y) make_pair(

Codeforces Round #404 (Div. 2) C 二分,水 D 数学,好题 E 分块

Codeforces Round #404 (Div. 2) C. Anton and Fairy Tale 题意:仓库容量n,每天运来m粮食,第 i 天被吃 i 粮食,问第几天仓库第一次空掉. tags:==SB题 注:二分边界判断,数据范围爆long long判断. // CF404 C #include<bits/stdc++.h> using namespace std; #pragma comment(linker, "/STACK:102400000,102400000&

Codeforces 506D Mr. Kitayuta&#39;s Colorful Graph(分块 + 并查集)

题目链接  Mr. Kitayuta's Colorful Graph 把每种颜色分开来考虑. 所有的颜色分为两种:涉及的点的个数 $> \sqrt{n}$    涉及的点的个数 $<= \sqrt{n}$ 对于第一种颜色,并查集缩点之后对每个询问依次处理过来若两点连通则答案加一. 对于第二种颜色,并查集所点之后对该颜色涉及的所有点两两之间判断是否连通, 若连通则另外开一个map记录答案. 最后把两个部分的答案加起来即可. 细节问题  由于每种颜色处理完之后并查集都要重新初始化,对于第一种颜色

Codeforces 785 E. Anton and Permutation(分块,树状数组)

Codeforces 785 E. Anton and Permutation 题目大意:给出n,q.n代表有一个元素从1到n的数组(对应索引1~n),q表示有q个查询.每次查询给出两个数l,r,要求将索引为l,r的两个数交换位置,并给出交换后数组中的逆序对数. 思路:此题用到了分块的思想,即将这组数分为bsz块,在每一块上建Fenwick树,对于每次查询,只需要处理l,r中间的块和l,r所在块受影响的部分.具体实现见代码及注释. #include<iostream> #include<