【bzoj4765】 普通计算姬

题意

  给出一棵有根树,$n$个点每个都有一个点权。$m$组操作每次可以修改一个点权或者询问编号在区间$[l,r]$的点的子树权值和的和。

Solution

  我们对节点编号分块,每一块统计该块中的节点的子树权值和的和。dfs处理出修改一个节点,需要对应修改它的祖先和它的所在的哪些块。另外再开一个树状数组,树状数组中每一个元素是对应dfs的点的权值,这样我们可以求出任意子树的权值和。

  对于询问,在中间的块直接统计。两侧零散的块在树状数组上暴力查询子树权值和。所以令块的大小$S=\sqrt{n/\log{n}}$,复杂度$O(n\sqrt{n\log{n}})$

细节

  会爆long long

代码

// bzoj4765
#include<algorithm>
#include<iostream>
#include<cstdlib>
#include<cstring>
#include<cstdio>
#include<cmath>
#define LL long long
#define ULL unsigned long long
#define inf (1ll<<30)
#define Pi acos(-1.0)
#define free(a) freopen(a".in","r",stdin),freopen(a".out","w",stdout)
using namespace std;

const int maxn=100010;
int head[maxn],L[maxn],R[maxn],t[maxn][350],pos[maxn],n,m,S,bn,cnt,dfn,Dargen;
LL c[maxn],d[maxn],a[maxn];
ULL s[maxn];
struct edge {int to,next;}e[maxn<<1];

int lowbit(int x) {
	return x&-x;
}
void add(int x,LL val) {
	for (int i=x;i<=n;i+=lowbit(i)) c[i]+=val;
}
LL query(int x) {
	LL res=0;
	for (int i=x;i;i-=lowbit(i)) res+=c[i];
	return res;
}
void link(int u,int v) {
	e[++cnt]=(edge){v,head[u]};head[u]=cnt;
	e[++cnt]=(edge){u,head[v]};head[v]=cnt;
}
LL dfs(int x,int fa) {
	L[x]=++dfn;d[pos[x]]++;
	LL sum=a[x];add(L[x],a[x]);
	for (int i=1;i<=bn;i++) t[x][i]=d[i];
	for (int i=head[x];i;i=e[i].next) if (e[i].to!=fa) sum+=dfs(e[i].to,x);
	R[x]=dfn;d[pos[x]]--;s[pos[x]]+=sum;
	return sum;
}
int main() {
	scanf("%d%d",&n,&m);
	S=300;bn=n/S+(n%S!=0);
	for (int i=1;i<=n;i++) pos[i]=(i-1)/S+1;
	for (int i=1;i<=n;i++) scanf("%lld",&a[i]);
	for (int u,v,i=1;i<=n;i++) {
		scanf("%d%d",&u,&v);
		if ((LL)u*v==0) Dargen=u+v;
		else link(u,v);
	}
	dfs(Dargen,0);
	for (int op,x,y,i=1;i<=m;i++) {
		scanf("%d%d%d",&op,&x,&y);
		if (op==1) {
			LL d=y-a[x];a[x]=y;
			for (int j=1;j<=bn;j++) s[j]+=d*t[x][j];
			add(L[x],d);
		}
		if (op==2) {
			ULL ans=0;
			if (pos[x]==pos[y]) for (int j=x;j<=y;j++) ans+=query(R[j])-query(L[j]-1);
			else {
				for (int j=pos[x]+1;j<pos[y];j++) ans+=s[j];
				for (int j=x;j<=S*pos[x];j++) ans+=query(R[j])-query(L[j]-1);
				for (int j=(pos[y]-1)*S+1;j<=y;j++) ans+=query(R[j])-query(L[j]-1);
			}
			printf("%llu\n",ans);
		}
	}
	return 0;
}
时间: 2024-11-25 06:59:43

【bzoj4765】 普通计算姬的相关文章

[BZOJ4765]普通计算姬

试题描述 "奋战三星期,造台计算机".小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]

【Foreign】无聊的计算姬 [Lucas][BSGS]

无聊的计算姬 Time Limit: 10 Sec  Memory Limit: 256 MB Description Input Output Sample Input 6 2 2 3 4 3 2 7 9 2 1 2 9 3 1 6 7 1 5 3 7 1 9 2 8 Sample Output Math Error 3 Math Error 6 6 1 HINT Source 我们可以分步骗分.(Task1直接快速幂即可.) 对于前50分: 对于Task2,我们直接暴力枚举,出现一个重复的停

bzoj 4766: 文艺计算姬 -- 快速乘

4766: 文艺计算姬 Time Limit: 1 Sec  Memory Limit: 128 MB Description "奋战三星期,造台计算机".小W响应号召,花了三星期造了台文艺计算姬.文艺计算姬比普通计算机有更多的艺 术细胞.普通计算机能计算一个带标号完全图的生成树个数,而文艺计算姬能计算一个带标号完全二分图的生成树 个数.更具体地,给定一个一边点数为n,另一边点数为m,共有n*m条边的带标号完全二分图K_{n,m},计算姬能快 速算出其生成树个数.小W不知道计算姬算的对

BZOJ4766: 文艺计算姬

Time Limit: 1 Sec  Memory Limit: 128 MBSubmit: 737  Solved: 402[Submit][Status][Discuss] Description "奋战三星期,造台计算机".小W响应号召,花了三星期造了台文艺计算姬.文艺计算姬比普通计算机有更多的艺 术细胞.普通计算机能计算一个带标号完全图的生成树个数,而文艺计算姬能计算一个带标号完全二分图的生成树 个数.更具体地,给定一个一边点数为n,另一边点数为m,共有n*m条边的带标号完全二

【bzoj4765】普通计算姬(双重分块)

题目传送门:http://www.lydsy.com/JudgeOnline/problem.php?id=4765 这道题已经攒了半年多了...因为懒,一直没去写...所以今天才把这道题写出来... 如果是要维护区间权值和.子树权值和,都可以用线段树/树状数组轻松解决.但是这道题要维护的是子树权值和的区间和,这就比较难搞了. 当需要维护一些看起来很难直接维护的信息时,我们一般会想到分块.于是考虑这样的分块:按编号把每√n个节点划分为一块,维护每一块所有节点的sum值的和,然后再维护每个节点的s

总结与心得(持续更新)

不知道为什么,刚学的算法过了2个月就忘得一干二净,我并没有背代码啊,当时学的时候还刷了好多题来着→_→,我是不是大脑能力严重衰退了. 动态规划 单调队列 一般情况下,${dp}$方程可以搞成这样:${f_i=f_j+t_j+t_i}$,只要其中没有变量同时与${i,j}$都有关,那么我们可以用单调队列来做,单调队列里面元素的关键字就是与${j}$有关的东西${f_j+t_j}$.example:生产产品 有些比较特殊的,虽然存在同时与${i,j}$相关的函数,但是这个函数比较简单,使得已经存在在

[BZOJ]2017省队十连测推广赛1

听学长说有比赛就随便打一打. A.普通计算姬 题目大意:给出一棵带权树,支持一下两种操作:1.修改一个点的权值:2.给出l,r,询问以点l为根的子树和.点l+1为根的子树和.点l+2为根的子树和--点r为根的子树和的总和.(点数.操作数不超过10^5) 思路:感觉是三题中最难的.给出的[l,r]区间在树上没有实际意义,不好利用数据结构维护.考虑若不修改,可以一遍dfs算出每个点对应的dfs序,这样每棵子树都对应一个dfs序的区间,前缀和一下就能O(1)查子树和,再按点的编号顺序把子树和前缀和一下

bzoj省选十连测推广赛

A.普通计算姬 题意:给丁一棵树,每个点有一个权值,用sum(x)表示以x为根的子树的权值和,要求支持两种操作: 1 u v  :修改点u的权值为v. 2 l  r   :  求∑sum[i] l<=i<=r n,m(操作数)<=10^5 题解:数据范围比较小,考虑分块重建的做法. 求出每个点的dfs序和子树的区间,这样就可以On建出所有节点的sum的前缀和. 然后每次修改操作都把操作存下来,每次查询先找出这段区间的和,再去操作里处理这些操作对这个查询的影响. 具体实现就是:把每个点的子

行列式 矩阵 重难点

把行列式与矩阵的基础给拾起来. 未完待续. 1. 行列式的递归定义与逆序对定义是等价的. 2. 行列式的性质 3. 三角行列式, 行列式求值, 高斯消元法 4. 奇阶反对称行列式 5. 例6. 6. 范徳蒙行列式 习题30. 习题44. 7. 一个分块技巧 文艺计算姬. 8. 递推思想 轮状病毒. 习题42. 习题39. 习题43. 9. 克拉默法则 10. 三角形面积 11. 习题28. 12. 矩阵乘法的性质 13. 坐标变换 旋转 14. 矩阵乘积的行列式 15. 伴随矩阵 16. 逆矩阵