题面:https://www.codechef.com/problems/FNCS
题解:
我们考虑对 n 个函数进行分块,设块的大小为S。
每个块内我们维护当前其所有函数值的和,以及数组中每个元素对这个块函数值的和的贡献系数。
那么每次修改操作我们就可以对每个块函数值的和 O(1)进行修改。
对于询问,落在完整块内的部分我们维护了它的和,直接 O(1)调用即可。
剩余的部分我们对每个函数依次求值。
那么现在问题就变为单点修改、询问区间和。
如果我们使用树状数组,那么单次询问与单次修改复杂度操作均为 O(logn),
而询问操作数目远多于修改操作导致时间效率不平衡。
所以我们对原数组求一遍前缀和,然后问题变为区间修改、单点查询,
这个我们用分块便可以做到 O(S+n/S)修改和 O(1)询问了。
PS:此题卡long long,要用unsigned long long。。。
code:
1 #include<cstdio> 2 #include<iostream> 3 #include<cmath> 4 #include<cstring> 5 #include<algorithm> 6 using namespace std; 7 char ch; 8 bool ok; 9 void read(int &x){ 10 for (ok=0,ch=getchar();!isdigit(ch);ch=getchar()) if (ch=='-') ok=1; 11 for (x=0;isdigit(ch);x=x*10+ch-'0',ch=getchar()); 12 if (ok) x=-x; 13 } 14 typedef unsigned long long int64; 15 const int maxs=320; 16 const int maxn=100005; 17 int n,q,siz,lim,op,l,r,x,y,bel[maxn]; 18 struct Data{ 19 int l,r; 20 }block[maxs],seg[maxn]; 21 int a[maxn]; 22 int f[maxs][maxn]; 23 int64 res[maxs],sum[maxs][maxs],tag[maxs]; 24 struct Seg{ 25 int add[maxn<<2]; 26 void init(){memset(add,0,sizeof(add));} 27 void pushdown(int k){if (add[k]) add[k<<1]+=add[k],add[(k<<1)+1]+=add[k],add[k]=0;} 28 void modify(int k,int l,int r,int x,int y){ 29 if (l==x&&r==y){add[k]++;return;} 30 int m=(l+r)>>1; 31 if (y<=m) modify(k<<1,l,m,x,y); 32 else if (x<=m) modify(k<<1,l,m,x,m),modify((k<<1)+1,m+1,r,m+1,y); 33 else modify((k<<1)+1,m+1,r,x,y); 34 } 35 void get(int k,int l,int r,int id){ 36 if (l==r){f[id][l]=add[k],res[id]+=1ULL*add[k]*a[l];return;} 37 int m=(l+r)>>1; 38 pushdown(k); 39 get(k<<1,l,m,id),get((k<<1)+1,m+1,r,id); 40 } 41 }T; 42 void add(int x,int v){ 43 int id=bel[x],st=id; 44 if (x>block[id].l){ 45 for (int i=x;i<=block[id].r;i++) sum[id][i-block[id].l]+=v; 46 st++; 47 } 48 for (int i=st;i<=lim;i++) tag[i]+=v; 49 } 50 int64 query(int x){ 51 if (!x) return 0; 52 int id=bel[x]; 53 return sum[id][x-block[id].l]+tag[id]; 54 } 55 void modify(int x,int v){ 56 add(x,-a[x]); 57 for (int i=1;i<=lim;i++) res[i]-=1ULL*f[i][x]*a[x]; 58 a[x]=v; 59 add(x,a[x]); 60 for (int i=1;i<=lim;i++) res[i]+=1ULL*f[i][x]*a[x]; 61 } 62 void query(int l,int r){ 63 int64 ans=0; 64 int st=bel[l],ed=bel[r]; 65 if (st!=ed){ 66 if (l>block[st].l){ 67 for (int i=l;i<=block[st].r;i++) ans+=query(seg[i].r)-query(seg[i].l-1); 68 st++; 69 } 70 if (r<block[ed].r){ 71 for (int i=block[ed].l;i<=r;i++) ans+=query(seg[i].r)-query(seg[i].l-1); 72 ed--; 73 } 74 for (int i=st;i<=ed;i++) ans+=res[i]; 75 } 76 else for (int i=l;i<=r;i++) ans+=query(seg[i].r)-query(seg[i].l-1); 77 printf("%llu ",ans); 78 } 79 int main(){ 80 read(n),siz=sqrt(n); 81 for (int i=1;i<=n;i++){ 82 bel[i]=i/siz+1; 83 if (!block[bel[i]].l) block[bel[i]].l=i; 84 block[bel[i]].r=i; 85 } 86 lim=bel[n]; 87 for (int i=1;i<=n;i++) read(a[i]),add(i,a[i]); 88 for (int i=1;i<=n;i++){ 89 if (block[bel[i]].l==i) T.init(); 90 read(l),read(r),seg[i]=(Data){l,r}; 91 T.modify(1,1,n,l,r); 92 if (block[bel[i]].r==i) T.get(1,1,n,bel[i]); 93 } 94 for (read(q);q;q--){ 95 read(op),read(x),read(y); 96 if (op==1) modify(x,y); 97 else query(x,y); 98 } 99 return 0; 100 }