[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^50<=Di,V<2^31,1<=L<=R<=N,1<=U<=NOutput
对每个操作类型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 5Sample Output
16
10
9HINT
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 }