[bzoj4765]普通计算姬(分块+树状数组+DFS序)
题意
给定一棵n个节点的带权树,节点编号为1到n,以root为根,设sum[p]表示以点p为根的这棵子树中所有节点的权值和。
计算姬支持下列两种操作: 1 给定两个整数u,v,修改点u的权值为v。 2 给定两个整数l,r,计算sum[l]+sum[l+1]+….+sum[r-1]+sum[r]
N<=10^5,M<=10^5
题解
每一个块中统计sum[i]的和,这个直接求出DFS序维护树状数组nlogn统计就行。
然后询问时对于一个整块直接加上我们统计的sum[i]的和,然后对于边角余料,我们用树状数组求就行。
修改时我们要维护树状数组直接位置上加(x-v[i])就行。
然后我们要维护块的和,就需要把和加上块中i的祖先数(包含i)*(x-v[i])。
所以我们预处理出f[i][j]代表第i块中j(包括j)的祖先数。这个dfs中用一个数组记录祖先情况(进入时加上自己,推出时减掉自己),对于每个点扫一遍每个块统计就行。
然后这题要用unsigned long long 然后也不能全开,会MLE
1 #include<iostream> 2 #include<cstring> 3 #include<cstdio> 4 #include<cmath> 5 #include<algorithm> 6 using namespace std; 7 const int N=100100; 8 int cnt,head[N]; 9 int size[N],id[N],tot; 10 int num[400],block[N],f[400][N]; 11 unsigned long long sum[400],a[N],tr[N],ans,v[N]; 12 int n,m,R[400],L[400],Block,root; 13 struct edge{ 14 int to,nxt; 15 }e[N*2]; 16 void add(int u,int v){ 17 cnt++; 18 e[cnt].nxt=head[u]; 19 e[cnt].to=v; 20 head[u]=cnt; 21 } 22 void dfs1(int u,int fa){ 23 size[u]=1; 24 id[u]=++tot; 25 for(int i=head[u];i;i=e[i].nxt){ 26 int v=e[i].to; 27 if(v==fa)continue; 28 dfs1(v,u); 29 size[u]+=size[v]; 30 } 31 } 32 void dfs2(int u,int fa){ 33 num[block[u]]++; 34 for(int i=1;i<=block[n];i++){ 35 f[i][u]+=num[i]; 36 } 37 for(int i=head[u];i;i=e[i].nxt){ 38 int v=e[i].to; 39 if(v==fa)continue; 40 dfs2(v,u); 41 } 42 num[block[u]]--; 43 } 44 int lowbit(int x){ 45 return x&-x; 46 } 47 void update(int x,unsigned long long w){ 48 for(int i=x;i<=n;i+=lowbit(i)){ 49 tr[i]+=w; 50 } 51 } 52 unsigned long long query(int x){ 53 unsigned long long tmp=0; 54 for(int i=x;i;i-=lowbit(i)){ 55 tmp+=tr[i]; 56 } 57 return tmp; 58 } 59 int main(){ 60 scanf("%d%d",&n,&m); 61 for(int i=1;i<=n;i++){ 62 scanf("%llu",&v[i]); 63 } 64 for(int i=1;i<=n;i++){ 65 int u,v; 66 scanf("%d%d",&u,&v); 67 if(u==0){ 68 root=v; 69 continue; 70 } 71 add(u,v); 72 add(v,u); 73 } 74 dfs1(root,0); 75 for(int i=1;i<=n;i++){ 76 update(id[i],v[i]); 77 } 78 for(int i=1;i<=n;i++){ 79 a[i]=query(id[i]+size[i]-1)-query(id[i]-1); 80 // cout<<i<<" "<<id[i]<<" "<<size[i]<<" "<<a[i]<<endl; 81 } 82 Block=sqrt(n); 83 for(int i=1;i<=n;i++){ 84 block[i]=(i-1)/Block+1; 85 sum[block[i]]+=a[i]; 86 if(!L[block[i]])L[block[i]]=i; 87 R[block[i]]=i; 88 } 89 dfs2(root,0); 90 while(m--){ 91 int k,x,y; 92 scanf("%d%d%d",&k,&x,&y); 93 if(k==1){ 94 for(int i=1;i<=block[n];i++){ 95 sum[i]+=f[i][x]*(y-v[x]); 96 } 97 update(id[x],y-v[x]); 98 v[x]=y; 99 } 100 else{ 101 ans=0; 102 if(block[x]+1>=block[y]){ 103 for(int i=x;i<=y;i++){ 104 ans+=query(id[i]+size[i]-1)-query(id[i]-1); 105 } 106 } 107 else{ 108 for(int i=block[x]+1;i<=block[y]-1;i++){ 109 ans+=sum[i]; 110 } 111 for(int i=x;i<=R[block[x]];i++){ 112 ans+=query(id[i]+size[i]-1)-query(id[i]-1); 113 } 114 for(int i=L[block[y]];i<=y;i++){ 115 ans+=query(id[i]+size[i]-1)-query(id[i]-1); 116 } 117 } 118 printf("%llu\n",ans); 119 } 120 } 121 return 0; 122 }