【bzoj4765】普通计算姬(双重分块)
题目传送门:http://www.lydsy.com/JudgeOnline/problem.php?id=4765
这道题已经攒了半年多了。。。因为懒,一直没去写。。。所以今天才把这道题写出来。。。
如果是要维护区间权值和、子树权值和,都可以用线段树/树状数组轻松解决。但是这道题要维护的是子树权值和的区间和,这就比较难搞了。
当需要维护一些看起来很难直接维护的信息时,我们一般会想到分块。于是考虑这样的分块:按编号把每√n个节点划分为一块,维护每一块所有节点的sum值的和,然后再维护每个节点的sum值。单节点的sum可以用树状数组/线段树维护,但为了降低时间复杂度,我们可以用分块维护dfs序的区间和的前缀和,这样的单节点修改复杂度为O(√n),单节点查询复杂度为O(1)。
时间复杂度:修改操作O(√n),查询操作O(√n),总时间复杂度O((n+m)√n)。
具体实现细节:维护第一层分块(即sum值的和)时可以在dfs遍历树时一个数组记录每个节点修改时对每个块的贡献,然后修改时直接统计贡献修改块的值就行了;第二层分块(即单节点的sum)时可以分别维护块的前缀和与每个节点在所在块内的前缀和,查询时把两部分加起来就行了。
另外,答案要开unsigned long long!
代码:
#include<cstdio>
#include<cstring>
#include<cmath>
#include<cstdlib>
#include<ctime>
#include<algorithm>
#include<queue>
#include<vector>
#define ll long long
#define ull unsigned long long
#define max(a,b) (a>b?a:b)
#define min(a,b) (a<b?a:b)
#define inf 0x3f3f3f3f
#define mod 1000000007
#define eps 1e-18
inline ll read()
{
ll tmp=; char c=getchar(),f=;
for(;c<''||''<c;c=getchar())if(c=='-')f=-;
for(;''<=c&&c<='';c=getchar())tmp=(tmp<<)+(tmp<<)+c-'';
return tmp*f;
}
using namespace std;
struct edge{
int to,nxt;
}e[];
int fir[],l[],r[],pos[];
ull sum1[],sum2[];
int a[],tmp[];
ull sum[];
int w[][];
int n,m,size,tot=,root;
void addedge(int x,int y){e[tot].to=y; e[tot].nxt=fir[x]; fir[x]=tot++;}
void dfs(int now,int fa)
{
if(now!=root){
for(int i=;i*size<n;i++)w[now][i]=w[fa][i];
}
++w[now][now/size]; l[now]=tot; pos[now]=tot++;
for(int i=fir[now];~i;i=e[i].nxt)
if(e[i].to!=fa)dfs(e[i].to,now);
r[now]=tot-;
}
void add(int x,int k)
{
int i,id=pos[x]/size;
a[x]+=k;
for(i=id;i*size<n;i++)sum1[i]+=k;
for(i=pos[x];i<(id+)*size&&i<n;i++)sum2[i]+=k;
for(i=;i*size<n;i++)sum[i]+=1ll*w[x][i]*k;
}
ull getsum(int x)
{
if(x<)return ;
else return sum2[x]+(x<size?:sum1[x/size-]);
}
ull query(int L,int R)
{
int i,idL=L/size,idR=R/size;
ull ans=;
if(idL==idR){
for(i=L;i<=R;i++)ans+=getsum(r[i])-getsum(l[i]-);
}
else{
for(i=idL+;i<idR;i++)ans+=sum[i];
for(i=L;i<(idL+)*size&&i<n;i++)ans+=getsum(r[i])-getsum(l[i]-);
for(i=idR*size;i<=R;i++)ans+=getsum(r[i])-getsum(l[i]-);
}
return ans;
}
int main()
{
int i;
n=read(); m=read(); size=(int)sqrt(n);
for(i=;i<n;i++)tmp[i]=read();
for(i=;i<n;i++)fir[i]=-;
for(i=;i<=n;i++){
int x=read(),y=read();
if(!x)root=y-;
else addedge(x-,y-),addedge(y-,x-);
}
tot=; dfs(root,-);
for(i=;i<n;i++)add(i,tmp[i]);
for(i=;i<=m;i++){
int op=read(),x=read(),y=read();
if(op==)add(x-,y-a[x-]);
else printf("%llu\n",query(x-,y-));
}
return ;
}
又臭又长
【bzoj4765】普通计算姬(双重分块)的更多相关文章
- [bzoj4765]普通计算姬(分块+树状数组+DFS序)
题意 给定一棵n个节点的带权树,节点编号为1到n,以root为根,设sum[p]表示以点p为根的这棵子树中所有节点的权值和.计算姬支持下列两种操作: 1 给定两个整数u,v,修改点u的权值为v. 2 ...
- BZOJ4765 普通计算姬(分块+树状数组)
对节点按编号分块.设f[i][j]为修改j号点对第i块的影响,计算f[i][]时dfs一遍即可.记录每一整块的sum.修改时对每一块直接更新sum,同时用dfs序上的树状数组维护子树和.查询时累加整块 ...
- bzoj4765: 普通计算姬 (分块 && BIT)
最近一直在刷分块啊 似乎感觉分块和BIT是超级棒的搭档啊 这道题首先用dfs预处理一下 得到每一个sum值 此时查询是O(1)的 (前缀和乱搞什么的 但是修改需要O(n) (需要修改该节点所有祖先的 ...
- BZOJ4765: 普通计算姬
BZOJ4765: 普通计算姬 题目描述 传送门 题目分析 求的和非常奇怪,不具有连续性,所有上树的数据结构全死了. 考虑分块,思考对于一段连续的询问区间可以直接询问整块,零散块可以在树上dfs序暴力 ...
- BZOJ_4765_普通计算姬_分块+dfs序+树状数组
BZOJ_4765_普通计算姬_分块 Description "奋战三星期,造台计算机".小G响应号召,花了三小时造了台普通计算姬.普通计算姬比普通计算机要厉害一些 .普通计算机能 ...
- [BZOJ4765]普通计算姬(分块+树状数组)
4765: 普通计算姬 Time Limit: 30 Sec Memory Limit: 256 MBSubmit: 1725 Solved: 376[Submit][Status][Discus ...
- 2018.06.30 BZOJ4765: 普通计算姬(dfs序+分块+树状数组)
4765: 普通计算姬 Time Limit: 30 Sec Memory Limit: 256 MB Description "奋战三星期,造台计算机".小G响应号召,花了三小时 ...
- [bzoj4765]普通计算姬——分块
Brief Description 给定一棵n个节点的带权树,节点编号为1到n,以root为根,设sum[p]表示以点p为根的这棵子树中所有节点的权 值和.支持下列两种操作: 1 给定两个整数u,v, ...
- BZOJ 4765 普通计算姬 (分块 + BIT)
4765: 普通计算姬 Time Limit: 30 Sec Memory Limit: 256 MBSubmit: 1547 Solved: 329[Submit][Status][Discus ...
- bzoj 4765 普通计算姬 dfs序 + 分块
题目链接 Description "奋战三星期,造台计算机".小G响应号召,花了三小时造了台普通计算姬.普通计算姬比普通计算机要厉害一些.普通计算机能计算数列区间和,而普通计算姬能 ...
随机推荐
- charles_https_通过模拟器安装APP然后抓包
声明,方法参考链接:https://bbs.pediy.com/thread-226435.htm 使用文中的模拟器并不好使,自个使用逍遥模拟器的4.4版本成功抓包, 1>下载逍遥模拟器,在逍遥 ...
- 错误命令“if not exist "\Dll" mkdir "\Dll" xcopy "\bin\Debug\*.*" "F:\647\VS项目\EtrolMes2014SY\Framework\Dll" /e /i /y”已退出,代码为 9009
分析错误 第一步:观察错误,发现plugin文件夹中未生成对应的编译文件. 第二步:XCOPY命令无法执行,百度xcopy为何无法执行 第三步,搜索,发现环境变量未配置正确. 就是环境变量path(大 ...
- docker学习笔记(2) 构建镜像
一.手动构建一个简单镜像 我们以构建nginx的docker镜像为例:手动构建镜像 docker pull centos 安装基础镜像docker run --name mynginx -it ...
- 《从零开始学Swift》学习笔记(Day 25)——类和结构体定义
原创文章,欢迎转载.转载请注明:关东升的博客 Swift中的类和结构体定义的语法是非常相似的.类使用class关键词定义类,使用struct关键词定义结构体,它们的语法格式如下: class 类名 { ...
- Partial Sum
Partial Sum Accepted : 80 Submit : 353 Time Limit : 3000 MS Memory Limit : 65536 KB Partial Sum ...
- 程序如何在RAM ROM运行,内存分配与分区
关于RAM ROM RAM与ROM就是具体的存储空间,统称为存储器 RAM(random access memory):运行内存,CPU可以直接访问,读写速度非常快,但是不能掉电存储.它又分为: 动态 ...
- iOS反射:把对象直接转化成NSDictionary
在IOS的网络编程中,通常我们需要将一些实体数据保存到NSDictionary,在获得NSDictionary后即可直接使用iOS 5后的NSJSONSerialization类型的dataWithJ ...
- 利用Hibernate注解生成表
转自:http://blog.csdn.net/madison__/article/details/55677099 Hibernate4注释 @Entity(name = "tbl_use ...
- PHP查看目录下的所有文件
[1].[代码] [PHP]代码 跳至 [1] ? 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 ...
- python多进程编程(一)
multiprocessing模块介绍 python中的多线程无法利用多核优势,如果想要充分地使用多核CPU的资源(os.cpu_count()查看),在python中大部分情况需要使用多进程.Pyt ...