您的位置:首页 > 运维架构

CC NOV14 Chef and Churu 分块+BIT维护单点.

2017-12-11 20:19 204 查看
题意:长度为n的序列a,现在有n个函数f,第i个函数f[i]的值为(a[l[i]]+a[l[i]+1]...a[r[i]]).Q个操作

操作1:修改a[i]的值.

操作2:求f[l]+f[l+1]+..f[r]的值.

n,Q<=1e5.a[i]<=1e9.

可以用BIT O(logn)内求出一个f[i]的值 查询一次要O(nlogn) 总共O(Q*nlogn) TLE....

现在能在O(logn)内求出一个f[i].考虑对序列f进行分块.

用差分对每一块进行预处理,处理出这一块中每个a[i]出现的次数,同时维护该块的f[i]之和. 

对于修改 知道序列a中第p个位置在该块的出现次数,容易更新出该块f[i]之和 O(sqrt(n)).

对于查询,头尾两个非整块BIT暴力求出f[i] 中间块O(1)累加.O(sqrt(n)*logn+sqrt(n)).

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=1e5+5,M=450;
ll m,n,num,Q,L
,R
,c
,pos
;
ll a
;
unsigned long long val
,b
,cnt[M]
;
int lowbit(int x)
{
return x&-x;
}
void update(int x,ll val)
{
for(int i=x;i<N;i+=lowbit(i))
b[i]+=val;
}
ll sum(int x)
{
ll res=0;
for(int i=x;i>0;i-=lowbit(i))
res+=b[i];
return res;
}
void init()
{
m=(int)sqrt(n);
num=n/m;
if(n%m)
num++;
for(int i=1;i<=n;i++)
pos[i]=(i-1)/m+1;
for(int i=1;i<=num;i++)
{
memset(c,0,sizeof(c));
for(int j=(i-1)*m+1;j<=i*m&&j<=n;j++)
{
c[L[j]]++;
c[R[j]+1]--;
}
for(int k=1;k<=n;k++)
c[k]+=c[k-1],cnt[i][k]=c[k],val[i]+=c[k]*a[k];
}
}
ll ask(int l,int r)
{
ll res=0;
if(pos[l]==pos[r])
{
for(int i=l;i<=r;i++)
res+=sum(R[i])-sum(L[i]-1);
}
else
{
for(int i=l;i<=pos[l]*m;i++)
res+=sum(R[i])-sum(L[i]-1);
for(int i=(pos[r]-1)*m+1;i<=r;i++)
res+=sum(R[i])-sum(L[i]-1);
}
for(int i=pos[l]+1;i<pos[r];i++)
res+=val[i];
return res;
}
int main()
{
scanf("%lld",&n);
for(int i=1;i<=n;i++)
scanf("%lld",&a[i]),update(i,a[i]);
for(int i=1;i<=n;i++)
scanf("%lld%lld",&L[i],&R[i]);
init();
scanf("%lld",&Q);
ll op,l,r,p,x;
while(Q--)
{
scanf("%lld",&op);
if(op==1)
{
scanf("%lld%lld",&p,&x);
for(int i=1;i<=num;i++)
{
ll t=cnt[i][p];
val[i]=val[i]+t*(x-a[p]);
}
update(p,x-a[p]);
a[p]=x;
}
else
{
scanf("%lld%lld",&l,&r);
printf("%llu\n",ask(l,r));
}
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: