BZOJ_4765_普通计算姬_分块

Description

"奋战三星期,造台计算机"。小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]+sum[r]
尽管计算姬可以很快完成这个问题,可是小G并不知道它的答案是否正确,你能帮助他吗?

Input

第一行两个整数n,m,表示树的节点数与操作次数。
接下来一行n个整数,第i个整数di表示点i的初始权值。
接下来n行每行两个整数ai,bi,表示一条树上的边,若ai=0则说明bi是根。
接下来m行每行三个整数,第一个整数op表示操作类型。
若op=1则接下来两个整数u,v表示将点u的权值修改为v。
若op=2则接下来两个整数l,r表示询问。
N<=10^5,M<=10^5
0<=Di,V<2^31,1<=L<=R<=N,1<=U<=N

Output

对每个操作类型2输出一行一个整数表示答案。

Sample Input

6 4
0 0 3 4 0 1
0 1
1 2
2 3
2 4
3 5
5 6
2 1 2
1 1 1
2 3 6
2 3 5

Sample Output

16
10
9

对结点编号进行分块,树状数组维护dfs序。
先预处理出来i到根路径上经过了多少第j块内的点,预处理时间复杂度$O(n\sqrt n)$
修改时对所有块直接用刚才预处理出来的打标记,同时也要在树状数组上修改出来。
查询时整块直接加上标记,零散的在树状数组上暴力。
总时间复杂度$O(n\sqrt n logn)$,可过。
其实也可以对那些零散的修改$O(\sqrt n)$查询$O(1)$,能做到$O(n\sqrt n)$不过我写不过带log的。
 
代码:
#include <stdio.h>
#include <string.h>
#include <algorithm>
#include <math.h>
using namespace std;
#define N 100050
typedef unsigned long long ll;
int size,block,L[N],R[N],pos[N],n,m;
int dep[N],fa[N],head[N],to[N<<1],nxt[N<<1],val[N],cnt,root,poi[N][350],dfn[N],son[N];
ll sum[N],tag[N],s[N],c[N];
inline void add(int u,int v) {
to[++cnt]=v; nxt[cnt]=head[u]; head[u]=cnt;
}
void fix(int x,ll v) {
for(;x<=n;x+=x&(-x)) c[x]+=v;
}
ll inq(int x) {
ll re=0;
for(;x;x-=x&(-x)) re+=c[x]; return re;
}
void dfs(int x,int y) {
int i,j; fa[x]=y; dep[x]=dep[y]+1; sum[x]=val[x]; dfn[x]=++dfn[0];
poi[x][pos[x]]++;
for(i=head[x];i;i=nxt[i]) {
if(to[i]!=y) {
for(j=1;j<=block;j++) poi[to[i]][j]=poi[x][j];
dfs(to[i],x);
sum[x]+=sum[to[i]];
}
}
son[x]=dfn[0];
}
void modify(int x,int y) {
int i;
for(i=1;i<=block;i++) tag[i]+=1ll*y*poi[x][i];
}
ll query(int x,int y) {
int p=pos[x],q=pos[y],i;
ll ans=0;
if(p==q) {
for(i=x;i<=y;i++) ans+=inq(son[i])-inq(dfn[i]-1);
}else {
for(i=p+1;i<q;i++) ans+=s[i]+tag[i];
for(i=x;i<=R[p];i++) {
ans+=inq(son[i])-inq(dfn[i]-1);
}
for(i=L[q];i<=y;i++) {
ans+=inq(son[i])-inq(dfn[i]-1);
}
}
return ans;
}
int main() {
scanf("%d%d",&n,&m);
int i,x,y,opt,j; size=sqrt(n);
block=n/size;
for(i=1;i<=block;i++) {
L[i]=R[i-1]+1; R[i]=size*i;
for(j=L[i];j<=R[i];j++) {
pos[j]=i;
}
}
if(R[block]!=n) {
block++; L[block]=R[block-1]+1; R[block]=n;
for(i=L[block];i<=n;i++) pos[i]=block;
} for(i=1;i<=n;i++) scanf("%d",&i[val]);
for(i=1;i<=n;i++) {
scanf("%d%d",&x,&y);
if(x) {
add(x,y); add(y,x);
}else root=y;
}
dfs(root,0);
for(i=1;i<=n;i++) s[pos[i]]+=sum[i],fix(dfn[i],val[i]);
while(m--) {
scanf("%d%d%d",&opt,&x,&y);
if(opt==1) {
modify(x,-val[x]); fix(dfn[x],-val[x]);val[x]=y;
modify(x,val[x]); fix(dfn[x],val[x]);
}else {
printf("%llu\n",query(x,y));
}
}
}

BZOJ_4765_普通计算姬_分块+dfs序+树状数组的更多相关文章

  1. 计蒜客A1998 Ka Chang (分块+dfs序+树状数组)

    题意 给你一个\(1e5\)的有点权的树,有\(1e5\)个操作: 1.给第\(x\)层的点加上\(y\) 2.求以\(x\)为根的子树的点权和 思路 首先处理出层数为x的所有点 操作2一般都是用df ...

  2. HDU 5293 Tree chain problem 树形dp+dfs序+树状数组+LCA

    题目链接: http://acm.hdu.edu.cn/showproblem.php?pid=5293 题意: 给你一些链,每条链都有自己的价值,求不相交不重合的链能够组成的最大价值. 题解: 树形 ...

  3. [BZOJ1103][POI2007]大都市meg dfs序+树状数组

    Description 在经济全球化浪潮的影响下,习惯于漫步在清晨的乡间小路的邮递员Blue Mary也开始骑着摩托车传递邮件了.不过,她经常回忆起以前在乡间漫步的情景.昔日,乡下有依次编号为1..n ...

  4. 【bzoj3653】谈笑风生 DFS序+树状数组

    题目描述 给出一棵以1为根的有根树,q次询问,每次询问给出a和k,求点对 (b,c) 的数目,满足:a.b.c互不相同,b与a距离不超过k,且a和b都是c的祖先. 输入 输入文件的第一行含有两个正整数 ...

  5. HDU 3887:Counting Offspring(DFS序+树状数组)

    http://acm.hdu.edu.cn/showproblem.php?pid=3887 题意:给出一个有根树,问对于每一个节点它的子树中有多少个节点的值是小于它的. 思路:这题和那道苹果树是一样 ...

  6. Codeforces Round #225 (Div. 1) C. Propagating tree dfs序+树状数组

    C. Propagating tree Time Limit: 20 Sec Memory Limit: 256 MB 题目连接 http://codeforces.com/contest/383/p ...

  7. BZOJ 2434: [Noi2011]阿狸的打字机( AC自动机 + DFS序 + 树状数组 )

    一个串a在b中出现, 那么a是b的某些前缀的后缀, 所以搞出AC自动机, 按fail反向建树, 然后查询(x, y)就是y的子树中有多少是x的前缀. 离线, 对AC自动机DFS一遍, 用dfs序+树状 ...

  8. 【bzoj3881】[Coci2015]Divljak AC自动机+树链的并+DFS序+树状数组

    题目描述 Alice有n个字符串S_1,S_2...S_n,Bob有一个字符串集合T,一开始集合是空的. 接下来会发生q个操作,操作有两种形式: “1 P”,Bob往自己的集合里添加了一个字符串P. ...

  9. 2018.10.20 NOIP模拟 巧克力(trie树+dfs序+树状数组)

    传送门 好题啊. 考虑前面的32分,直接维护后缀trietrietrie树就行了. 如果#号不在字符串首? 只需要维护第一个#前面的字符串和最后一个#后面的字符串. 分开用两棵trie树并且维护第一棵 ...

随机推荐

  1. Java + Selenium + TestNG + Maven

    环境准备: 1. Java: Install Java jdk: Version: java 1.8 or aboveConfigure Java Environment Variables:Add ...

  2. css区分ie8/ie9/ie10/ie11 chrome firefox的代码

    以下是几个主要浏览器的css  hack汇总: 现有css样式为: .class{ color:red; } 判断IE8以上的浏览器才执行的代码/* IE8+ */ .class{ color:red ...

  3. JAVA调用数据库存储过程

    下面将举出JAVA对ORACLE数据库存储过程的调用          ConnUtils连接工具类:用来获取连接.释放资源 复制代码 package com.ljq.test; import jav ...

  4. orderBy新写法

    通常,我们处理排序规则的处理方法是在sql 语句中order by create_time desc, 但是这时我们需要从控制器中一步步找到该方法,操作多. 我们试着将业务逻辑拆分到控制器 中, 把排 ...

  5. Spring Security简明实践及相关国际化处理

    别人的都是最佳实践,因为我目前的设置没有按照参考文档推荐,还是采用DelegatingFilterProxy,所以我只能说简明实践.先贴我的applicationContext-security.xm ...

  6. Java虚拟机-垃圾收集器

    垃圾收集器(Garbage Collection, GC)的诞生引导出了三个问题: 哪些内存需要回收? 什么时候回收? 如何回收? 对于线程独占的三个区域(程序计数器.虚拟机栈.本地方法栈)不用过多的 ...

  7. java之web开发过滤器

    我们通常上网的时候都会遇到一个问题,看到一个视频之类的,想要点开观看,点击之后,网页 提醒你:您尚未登录,是否要登录?然后巴拉巴拉跑去输账号密码. 那么这就是一个过滤器的功能,当你要访问一个资源的时候 ...

  8. 利用分支限界法求解单源最短路(Dijkstra)问题

    分支限界法定义:采用Best fist search算法,并使用剪枝函数的算法称为分支界限法. 分支限界法解释:按Best first的原则,有选择的在其child中进行扩展,从而舍弃不含有最优解的分 ...

  9. .NET开发微信小程序-获取OpenId

    注:获取当前用户信息只需要用GetUserInfo这个方法就行.这里就不需要提了 前端代码: CallBack:回调函数 function GetOpenID(CallBack){ var appIn ...

  10. Python_doc文件写入SQLite数据库

    #docx文档题库包含很多段,每段一个题目,格式为:问题.(答案) #数据库datase.db中tiku表包含kechengmingcheng.zhanngji.timu.daan四个字段 impor ...