[BZOJ4765]普通计算姬(分块+树状数组)

4765: 普通计算姬

Time Limit: 30 Sec  Memory Limit: 256 MB
Submit: 1725  Solved: 376
[Submit][Status][Discuss]

Description

"奋战三星期,造台计算机"。小G响应号召,花了三小时造了台普通计算姬。普通计算姬比普通计算机要厉害一些
。普通计算机能计算数列区间和,而普通计算姬能计算树中子树和。更具体地,小G的计算姬可以解决这么个问题
:给定一棵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]
尽管计算姬可以很快完成这个问题,可是小G并不知道它的答案是否正确,你能帮助他吗?

Input

第一行两个整数n,m,表示树的节点数与操作次数。
接下来一行n个整数,第i个整数di表示点i的初始权值。
接下来n行每行两个整数ai,bi,表示一条树上的边,若ai=0则说明bi是根。
接下来m行每行三个整数,第一个整数op表示操作类型。
若op=1则接下来两个整数u,v表示将点u的权值修改为v。
若op=2则接下来两个整数l,r表示询问。
N<=10^5,M<=10^5
0<=Di,V<2^31,1<=L<=R<=N,1<=U<=N

Output

对每个操作类型2输出一行一个整数表示答案。

Sample Input

6 4
0 0 3 4 0 1
0 1
1 2
2 3
2 4
3 5
5 6
2 1 2
1 1 1
2 3 6
2 3 5

Sample Output

16
10
9

HINT

Source

[Submit][Status][Discuss]

因为每个点的编号都是给定的,所以任何基于连续序列的数据结构(如DFS序等)都会失效(听说KDT可做),于是分块。

然后分块也是有讲究的,这题用到了一个套路:f[i][j]表示节点i到根的路径上的有多少个点在第j块中(也就是修改i节点对第j块的贡献),这个直接DFS预处理出来即可。

这样我们整块直接使用f数组,两端暴力上DFS序+树状数组即可。

友情提醒:这题爆long long 。

 1 #include<cmath>
 2 #include<cstdio>
 3 #include<algorithm>
 4 #define rep(i,l,r) for (int i=l; i<=r; i++)
 5 #define For(i,x) for (int i=h[x],k; i; i=nxt[i])
 6 typedef unsigned long long ll;
 7 using namespace std;
 8 
 9 const int N=100100;
10 int n,m,bl,B,u,v,l,r,cnt,tim,op,rt;
11 int h[N],a[N],bel[N],nxt[N<<1],L[N],R[N],to[N<<1],f[N][320];
12 ll c[N],sm[320],s[N],ans;
13 void ins(int u,int v){ to[++cnt]=v; nxt[cnt]=h[u]; h[u]=cnt; }
14 
15 void add(int x,ll k){ for (; x<=n; x+=x&-x) c[x]+=k; }
16 ll que(int x){ ll res=0; for (; x; x-=x&-x) res+=c[x]; return res; }
17 
18 void dfs(int x,int fa){
19     rep(i,1,B) f[x][i]=f[fa][i];
20     f[x][bel[x]]++; L[x]=++tim; s[x]=a[x];
21     For(i,x) if ((k=to[i])!=fa) dfs(k,x),s[x]+=s[k];
22     R[x]=tim;
23 }
24 
25 int main(){
26     freopen("bzoj4765.in","r",stdin);
27     freopen("bzoj4765.out","w",stdout);
28     scanf("%d%d",&n,&m); bl=(int)sqrt(n); B=(n-1)/bl+1;
29     rep(i,1,n) scanf("%d",&a[i]),bel[i]=(i-1)/bl+1;
30     rep(i,1,n){
31         scanf("%d%d",&u,&v);
32         if (u==0) rt=v; else ins(u,v),ins(v,u);
33     }
34     dfs(rt,0); rep(i,1,n) sm[bel[i]]+=s[i],add(L[i],a[i]);
35     rep(i,1,m){
36         scanf("%d",&op);
37         if (op==1){
38             scanf("%d%d",&u,&v); add(L[u],v-a[u]);
39             rep(i,1,B) sm[i]+=1ll*(v-a[u])*f[u][i]; a[u]=v;
40         }else{
41             scanf("%d%d",&l,&r); ans=0; int x=bel[l],y=bel[r];
42             if (x==y) rep(i,l,r) ans+=que(R[i])-que(L[i]-1);
43             else{
44                 rep(i,l,x*bl) ans+=que(R[i])-que(L[i]-1);
45                 rep(i,(y-1)*bl+1,r) ans+=que(R[i])-que(L[i]-1);
46                 rep(i,x+1,y-1) ans+=sm[i];
47             }
48             printf("%llu\n",ans);
49         }
50     }
51     return 0;
52 }

 

posted @ 2018-04-11 19:08  HocRiser  阅读(191)  评论(0编辑  收藏  举报