[codechef FNCS]分块处理+树状数组

题目链接:https://vjudge.net/problem/CodeChef-FNCS

在一个地方卡了一晚上,就是我本来以为用根号n分组,就会分成根号n个。事实上并不是。。。。因为用的是根号n下取整分组,得到的组数要用n/floor(sqrt(n))具体计算。

另外还有各种奇怪的bug……包括unsigned long long什么的……orz

#include<bits/stdc++.h>
using namespace std;
typedef unsigned long long ull;
const int maxn=100005;
int a[maxn];
int fl[maxn],fr[maxn];
int cnt[maxn][320];
ull res[320];
ull tree[maxn];
int N,block_size;

int lowbit(int x)
{
    return x&-x;
}

void add(int k,int x)
{
    while (k<=N)
    {
        tree[k]+=x;
        k+=lowbit(k);
    }
}

ull query(int k)
{
    ull res=0ull;
    while (k)
    {
        res+=tree[k];
        k-=lowbit(k);
    }
    return res;
}

void init(int n)
{
    N=n;
    for (int i=1;i<=N;i++) tree[i]=0ull;
}

ull query2(int k)
{
    if (k<1) return 0;
    ull r=0ull;
    int block_id=(k-1)/block_size+1;
    for (int i=1;i<block_id;i++) r+=res[i];
    for (int i=(block_id-1)*block_size+1;i<=k;i++)
    {
        r+=query(fr[i])-query(fl[i]-1);
    }
    return r;
}

int main()
{
    int n;
    scanf("%d",&n);
    for (int i=1;i<=n;i++) scanf("%d",&a[i]);
    for (int i=1;i<=n;i++) scanf("%d%d",&fl[i],&fr[i]);
    block_size=sqrt(n);
    int block=n/block_size;
    for (int i=1;i<=block;i++)
    {
        for (int j=(i-1)*block_size+1;j<=i*block_size;j++)
        {
            cnt[fr[j]+1][i]--;
            cnt[fl[j]][i]++;
        }
        res[i]=0;
        for (int j=1;j<=n;j++)
        {
            cnt[j][i]+=cnt[j-1][i];
            res[i]+=1ull*a[j]*cnt[j][i];
        }
    }
    init(n);
    for (int i=1;i<=n;i++) add(i,a[i]);
    int q;
    scanf("%d",&q);
    while (q--)
    {
        int op,x,y;
        scanf("%d%d%d",&op,&x,&y);
        if (op==2)
        {
            ull r=query2(y)-query2(x-1);
            printf("%llu\n",r);
        }
        else
        {
            for (int i=1;i<=block;i++)
            {
                res[i]+=1ull*cnt[x][i]*(y-a[x]);
            }
            add(x,y-a[x]);
            a[x]=y;
        }
    }
    return 0;
}
时间: 2024-10-23 13:29:38

[codechef FNCS]分块处理+树状数组的相关文章

[数据结构学习]分块与树状数组

分块与树状数组均在区间问题上有重要的应用 emm分块效率上不如树状数组,但是思路比较好想 先说分块: 将n个数的序列分为sqrt(n)块,预处理每块数据的信息以加快后续对区间信息的查询 先上一段代码: const int maxn = 5e5 + 50; int sum[maxn],a[maxn],l[maxn],r[maxn],belong[maxn]; int block,num; void build(){ block = sqrt(n); num = n/block; if(n%bloc

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<

【xsy2111】 【CODECHEF】Chef and Churus 分块+树状数组

题目大意:给你一个长度为$n$的数列$a_i$,定义$f_i=\sum_{j=l_i}^{r_i} num_j$. 有$m$个操作: 操作1:询问一个区间$l,r$请你求出$\sum_{i=l}^{r} f_i$. 操作2:将$a_x$变成$y$. 此题貌似正常做都不是很好做,考虑用一些奇奇怪怪的做法(比如说分块) 考虑到此题数列在不断地变化,我们考虑用树状数组来维护序列$a$,查询$f_i$的值可以在$O(log n)$的时间内完成. 如果这么做,单次询问的复杂度是$O(n log n)$的,

【BZOJ4167】永远的竹笋采摘 分块+树状数组

[BZOJ4167]永远的竹笋采摘 题解:我们考虑有多少点对(a,b)满足a与b的差值是[a,b]中最小的.以为是随机数据,这样的点对数目可能很少,实测是O(n)级别的,那么我们已知了有这么多可能对答案造成贡献的点对,如何将它们求出来呢? 考虑分块,因为所有数大小在[1,n]中,我们可以对于每个块,预处理出整个块到所有数的最小差值.然后从右往左枚举每一个点,再枚举右面所有的块,如果这个块到当前数的差值比之前的要小,那就暴力进入块中扫一遍.与此同时,我们需要知道是否已经存在这样的点对,被当前的点对

【bzoj3744】Gty的妹子序列 分块+树状数组+主席树

题目描述 我早已习惯你不在身边, 人间四月天 寂寞断了弦. 回望身后蓝天, 跟再见说再见…… 某天,蒟蒻Autumn发现了从 Gty的妹子树(bzoj3720) 上掉落下来了许多妹子,他发现 她们排成了一个序列,每个妹子有一个美丽度. Bakser神犇与他打算研究一下这个妹子序列,于是Bakser神犇问道:"你知道区间 [l,r]中妹子们美丽度的逆序对数吗?" 蒟蒻Autumn只会离线乱搞啊……但是Bakser神犇说道:"强制在线." 请你帮助一下Autumn吧.

【分块】【树状数组】bzoj3744 Gty的妹子序列

离散化,分块. 预处理出:ans[i][j] 第i块到第j块的逆序对数. f[i][j] 第1~i块中大于j的数的个数. g[i][j] 第1~j块中小于j的数的个数. 每次询问时对于整块部分可以O(1)获得. 对于零散部分呢? >在一列数的后面添加一个数,逆序对数会增加 数列中比它大的数的个数. >在一列数的前面添加一个数,逆序对数会增加 数列中比它小的数的个数. 所以统计以上信息的时候,对于整块的部分,我们可以借由预处理的东西差分来O(1)地获得答案,零散的部分就是树状数组咯. 空间复杂度

【树状数组】【权值分块】bzoj2352 Stars

经典问题:二维偏序.给定平面中的n个点,求每个点左下方的点的个数. 因为 所有点已经以y为第一关键字,x为第二关键字排好序,所以我们按读入顺序处理,仅仅需要计算x坐标小于<=某个点的点有多少个就行. 这就是所说的:n维偏序,一维排序,二维树状数组,三维 分治 Or 树状数组套平衡树…… <法一>树状数组. 1 #include<cstdio> 2 #include<algorithm> 3 #include<iostream> 4 using name

BZOJ 2141 排队 分块+树状数组

题目大意:给定一个序列,m次交换两个数,求初始逆序对数及每次交换后的逆序对数 首先离散化,分块,对于每块建立一个树状数组,保存这个块中的所有元素 然后对于每个询问(x,y) (x<y) 两侧的数是没有影响的,区间(x,y)的数a[i]讨论如下: a[i]<a[x] --ans a[i]>a[x] ++ans a[i]<a[y] ++ans a[i]>a[y] --ans 然后对于块中的树状数组处理,块外的暴力 注意此题元素有重复 亲测可信 RANK5吓尿0.0 为何块套树要比

hdu 5193 分块 树状数组 逆序对

题意: 给出n个数,a1,a2,a3,...,an,给出m个修改,每个修改往数组的某个位置后面插入一个数,或者把某个位置上的数移除.求每次修改后逆序对的个数. 限制: 1 <= n,m <= 20000; 1 <= ai <= n 思路: 插入和删除用分块来处理,块与块之间用双向链表来维护,每一块用树状数组来求小于某个数的数有多少个. 外层可以使用分块维护下标,这样添加和删除元素的时候,也很方便,直接暴力.查找权值个数时,使用树状数组比较方便.内层通过树状数组维护权值. 每次更新即