【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响应号召,花了三小时造了台普通计算姬.普通计算姬比普通计算机要厉害一些.普通计算机能计算数列区间和,而普通计算姬能 ...
随机推荐
- Android开发:TableFixHeaders源码分析
最近需要在android上的展示表格数据,在github上找到了TableFixHeaders(https://github.com/InQBarna/TableFixHeaders). 项目文件最主 ...
- azure iothub create-device-identity样例报错: unable to find valid certification path ,及iothub-explorer Error: CERT_UNTRUSTED
https://docs.microsoft.com/zh-cn/azure/iot-hub/iot-hub-java-java-getstarted 在IDEA中执行上述的代码,会出现下面的报错信息 ...
- c#数据格式转换汇总
时间差的公式,求出时间相差的转换成刻度值 DateTime endTime = , , , , , , , , , , , , ); TimeSpan temp = new TimeSpan(star ...
- distinct与NULL在count的注意事项
select * from errorinfo ) from errorinfo select distinct info from errorinfo select count(distinct i ...
- 【转】Power System 中基于 VIOS 的虚拟以太网实现
基于 VIOS 的虚拟以太网适配器的工作原理和配置实现 本文对 Power 系统中基于 VIOS 的虚拟以太网适配器(Virtual Ethernet Adapter)的工作原理.基本配置选项和配置步 ...
- 洛谷P5274 优化题(ccj)
洛谷P5274 优化题(ccj) 题目背景 CCJCCJ 在前往参加 Universe \ OIUniverse OI 的途中... 题目描述 有一个神犇 CCJCCJ,他在前往参加 Universe ...
- vloatile总结与synchronized对比
原文地址:https://www.cnblogs.com/xiaoxian1369/p/5411877.html 1.要使volatile变量提供理想的线程安全,必须同时满足以下两个条件:1).对变量 ...
- Redis3.2.8配置参数及说明
bind 127.0.0.1# 绑定的主机地址,不设置默认将处理所有请求protected-mode yes# 是否开启保护模式,默认开启,要是配置里面没有指定bind和密码,开启该参数后,redis ...
- C# 面向对象三大特性:封装、继承、多态
面向对象有封装.继承.多态这三个特性,面向对象编程按照现实世界的特点来管理复杂的事物,把它们抽象为对象,具有自己的状态和行为,通过对消息的反应来完成任务.这种编程方法提供了非常强大的多样性,大大增加了 ...
- 电信、网通、联通等恶意DNS劫持跳广告页面的解决方法
中国电信.网通.联通ADSL用户必读:中国电信.网通.联通劫持dns(中国电信.网通.联通劫持ie浏览器)解决方案D... 宽带连接有 也能上网但是本地连接一直显示为受限制的解决方法 我的电脑一直显示 ...