题目传送门: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】普通计算姬(双重分块)的更多相关文章

  1. [bzoj4765]普通计算姬(分块+树状数组+DFS序)

    题意 给定一棵n个节点的带权树,节点编号为1到n,以root为根,设sum[p]表示以点p为根的这棵子树中所有节点的权值和.计算姬支持下列两种操作: 1 给定两个整数u,v,修改点u的权值为v. 2 ...

  2. BZOJ4765 普通计算姬(分块+树状数组)

    对节点按编号分块.设f[i][j]为修改j号点对第i块的影响,计算f[i][]时dfs一遍即可.记录每一整块的sum.修改时对每一块直接更新sum,同时用dfs序上的树状数组维护子树和.查询时累加整块 ...

  3. bzoj4765: 普通计算姬 (分块 && BIT)

    最近一直在刷分块啊 似乎感觉分块和BIT是超级棒的搭档啊 这道题首先用dfs预处理一下 得到每一个sum值 此时查询是O(1)的  (前缀和乱搞什么的 但是修改需要O(n) (需要修改该节点所有祖先的 ...

  4. BZOJ4765: 普通计算姬

    BZOJ4765: 普通计算姬 题目描述 传送门 题目分析 求的和非常奇怪,不具有连续性,所有上树的数据结构全死了. 考虑分块,思考对于一段连续的询问区间可以直接询问整块,零散块可以在树上dfs序暴力 ...

  5. BZOJ_4765_普通计算姬_分块+dfs序+树状数组

    BZOJ_4765_普通计算姬_分块 Description "奋战三星期,造台计算机".小G响应号召,花了三小时造了台普通计算姬.普通计算姬比普通计算机要厉害一些 .普通计算机能 ...

  6. [BZOJ4765]普通计算姬(分块+树状数组)

    4765: 普通计算姬 Time Limit: 30 Sec  Memory Limit: 256 MBSubmit: 1725  Solved: 376[Submit][Status][Discus ...

  7. 2018.06.30 BZOJ4765: 普通计算姬(dfs序+分块+树状数组)

    4765: 普通计算姬 Time Limit: 30 Sec Memory Limit: 256 MB Description "奋战三星期,造台计算机".小G响应号召,花了三小时 ...

  8. [bzoj4765]普通计算姬——分块

    Brief Description 给定一棵n个节点的带权树,节点编号为1到n,以root为根,设sum[p]表示以点p为根的这棵子树中所有节点的权 值和.支持下列两种操作: 1 给定两个整数u,v, ...

  9. BZOJ 4765 普通计算姬 (分块 + BIT)

    4765: 普通计算姬 Time Limit: 30 Sec  Memory Limit: 256 MBSubmit: 1547  Solved: 329[Submit][Status][Discus ...

  10. bzoj 4765 普通计算姬 dfs序 + 分块

    题目链接 Description "奋战三星期,造台计算机".小G响应号召,花了三小时造了台普通计算姬.普通计算姬比普通计算机要厉害一些.普通计算机能计算数列区间和,而普通计算姬能 ...

随机推荐

  1. vue高级路由

    1.html <script src="https://unpkg.com/vue/dist/vue.js"></script><script src ...

  2. mac中一一些常用的命令

    本文转载至 http://blog.csdn.net/chen505358119/article/details/9244701   这里主要讲的是mac中的一些命令,怕忘记了所以记在这里. 1.首先 ...

  3. Android开发:TableFixHeaders源码分析

    最近需要在android上的展示表格数据,在github上找到了TableFixHeaders(https://github.com/InQBarna/TableFixHeaders). 项目文件最主 ...

  4. EF 批量更新删除(linq篇)

    刚开始用EF很多东西都不会用,事后想想都很简单的东西总是用很麻烦的方式实现 1:  EF的联合查询 inner join  很久很久以前我是这么写一个列表展示的,其中有两个字段Contractor和M ...

  5. MySQL 的约束

    约束是添加在列上, 用来约束列的! 1. 主键约束(表中的某行的唯一标识) 主键的特点: 非空 唯一 被引用 创建表时, 指定主键的两种方式: // 需求: 指定 sid 列为主键列, 即为 sid ...

  6. Python如何实现单例模式?其他23种设计模式python如何实现?

    #使用__metaclass__(元类)的高级python用法 class Singleton2(type): def __init__(cls, name, bases, dict): super( ...

  7. 笔记:zookeeper Hello World

    下载zookeeper-3.4.6 , 试用了一下 standlone 启动 ./bin/zkServer.sh start 注: Usage: ./bin/zkServer.sh {start|st ...

  8. 修改impala表location

    两种方式: 一.通过修改表DDL: alter table t_m_cc set location 'hdfs://heracles/user/video-mvc/hive/warehouse/t_m ...

  9. app开发多少钱一个

    经常听网友问app开发要多少钱,这个问题太宽泛了,需要根据具体的需求才好定价,也就是要先做好需求分析(前面我们写了一个app开发需求文档模板),不同的功能不同的价位,就像我们买电脑,cpu多少钱.主板 ...

  10. Java - 在控制台中执行一个可执行jar

    1.Maven打包一个可执行jar: <build> <plugins> <plugin> <groupId>org.apache.maven.plug ...