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

题目大意:给你一个长度为n的数列ai,定义fi=rij=linumj

m个操作:

操作1:询问一个区间l,r请你求出ri=lfi

操作2:将ax变成y

 

题貌似正常做都不是很好做,考虑用一些奇奇怪怪的做法(比如说分块)

考虑到此题数列在不断地变化,我们考虑用树状数组来维护序列a,查询fi的值可以在O(logn)的时间内完成。

如果这么做,单次询问的复杂度是O(nlogn)的,显然不行。

 

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

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

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

显然ans[i]=nj=1sum[i][j]×num[j]

 

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

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

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

 

对于修改操作;

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

 

总时间复杂度为O(n1.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\n",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\n",res);
39         }
40     }
41 }
复制代码

 

posted @   AlphaInf  阅读(271)  评论(0编辑  收藏  举报
编辑推荐:
· AI与.NET技术实操系列:基于图像分类模型对图像进行分类
· go语言实现终端里的倒计时
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
阅读排行:
· 25岁的心里话
· 闲置电脑爆改个人服务器(超详细) #公网映射 #Vmware虚拟网络编辑器
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· 零经验选手,Compose 一天开发一款小游戏!
· 一起来玩mcp_server_sqlite,让AI帮你做增删改查!!
点击右上角即可分享
微信分享提示