BZOJ4765 普通计算姬(分块+树状数组)
对节点按编号分块。设f[i][j]为修改j号点对第i块的影响,计算f[i][]时dfs一遍即可。记录每一整块的sum。修改时对每一块直接更新sum,同时用dfs序上的树状数组维护子树和。查询时累加整块区间的sum,剩余部分bit上暴力查询。分析一下复杂度。设块大小为k,计算f数组的复杂度为O(n2/k),修改复杂度为O(nm/k+mlogn),查询复杂度O(nm/k+mklogn)。不妨设nm同阶,则k=sqrt(n/logn)时最优,总复杂度O(n·sqrt(nlogn))。然而真的这样的话f空间不够反正直接开sqrt(n)就过了。
#include<iostream> #include<cstdio> #include<cmath> #include<cstdlib> #include<cstring> #include<algorithm> using namespace std; #define ll unsigned long long #define N 100010 #define BLOCK 320 char getc(){char c=getchar();while ((c<'A'||c>'Z')&&(c<'a'||c>'z')&&(c<'0'||c>'9')) c=getchar();return c;} int gcd(int n,int m){return m==0?n:gcd(m,n%m);} int read() { int x=0,f=1;char c=getchar(); while (c<'0'||c>'9') {if (c=='-') f=-1;c=getchar();} while (c>='0'&&c<='9') x=(x<<1)+(x<<3)+(c^48),c=getchar(); return x*f; } int n,m,p[N],dfn[N],size[N],root,t,cnt; int block,num,L[BLOCK],R[BLOCK],pos[N],f[BLOCK][N]; ll sum[BLOCK],tree[N],a[N]; struct data{int to,nxt; }edge[N<<1]; void addedge(int x,int y){t++;edge[t].to=y,edge[t].nxt=p[x],p[x]=t;} void add(int k,int x){while (k<=n) tree[k]+=x,k+=k&-k;} ll query(int k){ll s=0;while (k) s+=tree[k],k-=k&-k;return s;} void calc(int k,int x,int from,int cnt) { if (k>=L[x]&&k<=R[x]) cnt++; f[x][k]=cnt; for (int i=p[k];i;i=edge[i].nxt) if (edge[i].to!=from) calc(edge[i].to,x,k,cnt); } void dfs(int k,int from) { dfn[k]=++cnt;size[k]=1; for (int i=p[k];i;i=edge[i].nxt) if (edge[i].to!=from) dfs(edge[i].to,k),size[k]+=size[edge[i].to]; } int main() { #ifndef ONLINE_JUDGE freopen("bzoj4765.in","r",stdin); freopen("bzoj4765.out","w",stdout); const char LL[]="%I64u\n"; #else const char LL[]="%llu\n"; #endif n=read(),m=read(); for (int i=1;i<=n;i++) a[i]=read(); block=sqrt(n);num=(n-1)/block+1; for (int i=1;i<=num;i++) { L[i]=(i-1)*block+1,R[i]=min(n,i*block); for (int j=L[i];j<=R[i];j++) pos[j]=i; } for (int i=1;i<=n;i++) { int x=read(),y=read(); if (!x) root=y; else addedge(x,y),addedge(y,x); } for (int i=1;i<=num;i++) calc(root,i,root,0); dfs(root,root); for (int i=1;i<=n;i++) add(dfn[i],a[i]); for (int i=1;i<=n;i++) sum[pos[i]]+=query(dfn[i]+size[i]-1)-query(dfn[i]-1); while (m--) { int op=read(); if (op==1) { int x=read(),y=read(); y-=a[x]; add(dfn[x],y); for (int i=1;i<=num;i++) sum[i]+=(ll)f[i][x]*y; a[x]+=y; } else { int l=read(),r=read(); ll ans=0; if (pos[l]==pos[r]) { for (int i=l;i<=r;i++) ans+=query(dfn[i]+size[i]-1)-query(dfn[i]-1); } else { for (int i=pos[l]+1;i<pos[r];i++) ans+=sum[i]; for (int i=l;i<=R[pos[l]];i++) ans+=query(dfn[i]+size[i]-1)-query(dfn[i]-1); for (int i=L[pos[r]];i<=r;i++) ans+=query(dfn[i]+size[i]-1)-query(dfn[i]-1); } printf(LL,ans); } } return 0; }