【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响应号召,花了三小时造了台普通计算姬.普通计算姬比普通计算机要厉害一些.普通计算机能计算数列区间和,而普通计算姬能 ...
随机推荐
- 如何修改vs2005/vs2010的tfs的登录名和密码 .
如何修改vs2005/vs2010的tfs的登录名和密码 . 连接TFS时,如果本机保存了用户的网络密码,不会出现用户名和密码的输入框,若要更换TFS的用户名和密码,需按以下步骤操作: 控制面板--- ...
- IntelliJ IDEA使用手册
开发工具现在转到IDEA了,看到关于该工具很好的入门文档,于是记录一下: IntelliJ IDEA 使用教程
- poj1840
Eqs Time Limit: 5000MS Memory Limit: 65536K Total Submissions: 15133 Accepted: 7426 Description ...
- 《从零开始学Swift》学习笔记(Day 24)——枚举
原创文章,欢迎转载.转载请注明:关东升的博客 Swift中的枚举可以定义一组常量.提高程序的可读性:还具有面向对象特性. 使用enum关键词声明枚举类型,具体定义放在一对大括号内,枚举的语法格式如下 ...
- 【转】Gacutil.exe(全局程序集缓存工具)
全局程序集缓存工具使您可以查看和操作全局程序集缓存和下载缓存的内容. 安装 Visual Studio 和 Windows SDK 时会自动安装此工具. 要运行工具,我们建议您使用 Visual St ...
- jQuery实现局部刷新页面数据绑定
今天遇到了一个问题:怎么样才能做到只刷新页面中的Repeater控件中的数据,在不用UploadPannel的情况下? 试了好多方法,无意间在看jquery文件时发现,使用load()方法即可解决此问 ...
- 封装AJax实现JSON前台与后台交互
实践技术点:1.AJax自定义封装 2.后台序列化与反序列化JSON 3.客户端解析JSON字符串,处理DOM 实现代码如下: 1.JS脚本代码: 1 /*** NOTE:AJAX处理JS TIM ...
- 你意识到苹果公司已经抛弃了GC吗?
为什么移动Web应用程序很慢(译) - tangzhnju - 博客园 http://www.cnblogs.com/codemood/p/3213459.html
- Python电影投票系统
电影投票:程序先给出几个目前正在上映的电影列表. 由用户给每个电影投票.最终将该用户投票信息公布出来 lst = ['北京遇上西雅图', '解救吴先生', '美国往事', '西西里的美丽传说']结果: ...
- JDBC请求
做JDBC请求,首先需要两个jar包:mysql驱动-mysql-connector-java-5.1.13-bin.jar 和 sqlServer驱动-sqljdbc4.jar,将这两个jar包放到 ...