[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 }

 

posted @ 2018-08-16 16:02  Xu-daxia  阅读(177)  评论(0编辑  收藏  举报