• 【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)$的,显然不行。

    我们令第$k$块中包含有函数$f(kN),f(kN+1).......f(kN+(N-1))$。其中$N$是一个常数

    设$sum[i][j]$表示第i块中所有函数中数字$a_j$出现的次数。

    设$ans[i]$表示第i块所有函数之和。

    显然$ans[i]=sum_{j=1}^{n} sum[i][j] imes num[j]$。

    对于一个询问的区间,我们显然可以将其拆成尽可能多的块+不超过$2N$个单点;

    对于每个块的块的和,我们显然可以在$O(1)$的复杂度内完成求值。

    对于单点部分,我们直接查询就可以了。

    对于修改操作;

    首先我们更新树状数组,然后根据$sum[i][X]$的值来更新$ans[i]$即可,时间复杂度是$O(log n+sqrt{n})$。

    总时间复杂度为$O(n^{1.5} log  n)$

    这次的分块应该是编码效率最高的一次了

     1 #include<bits/stdc++.h>
     2 #define M 100005
     3 #define N 360
     4 #define lowbit(x) ((x)&(-(x)))
     5 #define L unsigned long long
     6 int n,m,l[M]={0},r[M]={0};
     7 int sum[320][M]={0},num[M]={0},bel[M]={0};
     8 L ans[M]={0},a[M]={0};
     9 void add(int x,int k){for(int i=x;i<=n;i+=lowbit(i)) a[i]+=k;}
    10 L Q(int x){L k=0; for(int i=x;i;i-=lowbit(i)) k+=a[i]; return k;}
    11 int main(){
    12     scanf("%d",&n);
    13     for(int i=1;i<=n;i++) bel[i]=(i+N-1)/N;
    14     for(int i=1;i<=n;i++) scanf("%d",num+i),add(i,num[i]);
    15     for(int i=1;i<=n;i++){
    16         scanf("%d%d",l+i,r+i);
    17         ans[bel[i]]+=Q(r[i])-Q(l[i]-1);
    18         sum[bel[i]][l[i]]++; sum[bel[i]][r[i]+1]--;
    19     }
    20     for(int x=1;x<=bel[n];x++)
    21         for(int i=1;i<=n;i++) sum[x][i]+=sum[x][i-1];
    22     scanf("%d",&m);
    23     while(m--){
    24         int op,X,Y;L res=0; scanf("%d%d%d",&op,&X,&Y);
    25         if(op==1){
    26             for(int x=1;x<=bel[n];x++)
    27             ans[x]+=1LL*sum[x][X]*(Y-num[X]);
    28             add(X,Y-num[X]); num[X]=Y;
    29         }else{
    30             if(bel[X]==bel[Y]){
    31                 for(int i=X;i<=Y;i++) res+=Q(r[i])-Q(l[i]-1);
    32                 printf("%llu
    ",res);
    33                 continue;
    34             }
    35             for(int x=bel[X]+1;x<bel[Y];x++) res+=ans[x];
    36             for(int i=X;bel[X]==bel[i];i++) res+=Q(r[i])-Q(l[i]-1);
    37             for(int i=Y;bel[Y]==bel[i];i--) res+=Q(r[i])-Q(l[i]-1);
    38             printf("%llu
    ",res);
    39         }
    40     }
    41 }
  • 相关阅读:
    Android:res之selector背景选择器
    工作备份 build.gradle
    Android studio听云接入另外一种方式
    自由开发者_免费可商用的图片资源推荐
    Duplicate files copied in APK META-INF/LICENSE.txt
    模仿九宫格拼音输入法,根据输入的数字键,形成对应的汉字拼音
    Map转Bean小工具
    验证身份证是否合法算法
    jqzoom插件图片放大功能的一些BUG
    外层div高度不随内层div高度改变的解决办法
  • 原文地址:https://www.cnblogs.com/xiefengze1/p/10354260.html
Copyright © 2020-2023  润新知