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

HINT

Source

感受到树上分块的邪恶力量!!!  %%%XLightGod;

貌似这题有很多种做法,主要是连续编号的子树和不是很好搞!!!

直接讲树上分块的做法好了,不想绕圈子:

子树和依据我们以前打树链剖分的时候(其实应该叫轻重链剖分,今天听到了一位NOI金牌爷说了个叫长链剖分的鬼玩意);

我们知道一个点的子树其实就是一段连续的dfs序;

首先对[1,n]分块,想到分块查询的基本思想

那么每次询问相当与是若干个整块加上剩下的几个点;

我们一步一步来解决:

首先对于每一个块的可以通过统计每个点在子树中出现的次数,那么我们可以通过O(n)的时间计算出整块贡献;

接下来的瓶颈就在于解决如何快速O(1)求出每个点的子树和

根据子树是dfs序中连续的一段我们可以考虑对dfs序进行分块,然后统计所有块的前缀和以及每个块自己内部的前缀和,通过前缀和的基本操作可以O(1)求解

附上代码:

// MADE BY QT666
#include<cstdio>
#include<algorithm>
#include<cmath>
#include<iostream>
#include<queue>
#include<set>
#include<cstdlib>
#include<cstring>
#include<string>
#include<ctime>
#define lson num<<1
#define rson num<<1|1
using namespace std;
typedef long long ll;
const int N=100001;
int gi()
{
int x=0,flag=1;
char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-') flag=-1;ch=getchar();}
while(ch>='0'&&ch<='9') x=x*10+ch-'0',ch=getchar();
return x*flag;
}
int head[N],to[N*2],nxt[N*2];
int v[N],pos[N],kp[N],dfn[N],id[N],block,num[320][N],fa[N],end[N];
int n,m,cnt,tt,cnt2,root;
unsigned long long tot1[N],tot2[320],tot3[320];
void dfs(int x,int f){
dfn[x]=++tt;id[tt]=x;
for(int i=head[x];i;i=nxt[i]){
int y=to[i];
if(y!=f){
fa[y]=x;dfs(y,x);
}
}
end[x]=tt;
}
inline void lnk(int x,int y){
to[++cnt]=y,nxt[cnt]=head[x],head[x]=cnt;
to[++cnt]=x,nxt[cnt]=head[y],head[y]=cnt;
}
unsigned long long query(int x){return tot3[pos[x]-1]+tot1[x];}
inline void make_tot1(){
for(int i=1;i<=n;i++) tot1[dfn[i]]=v[i];
for(int i=1;i<=n;i++) {if(kp[i]!=1) tot1[i]+=tot1[i-1];}
}
inline void make_tot2(){
for(int i=1;i<=cnt2;i++)
for(int j=1;j<=n;j++)
num[i][id[j]]=num[i][fa[id[j]]]+(pos[id[j]]==i);
for(int i=1;i<=cnt2;i++)
for(int j=1;j<=n;j++)
tot2[i]+=(unsigned long long)1ll*num[i][j]*v[j];
}
inline void make_tot3(){
for(int i=1;i<=n;i++) tot3[pos[dfn[i]]]+=v[i];
for(int i=1;i<=cnt2;i++) tot3[i]+=tot3[i-1];
}
int main()
{
freopen("1.in","r",stdin);
freopen("1.out","w",stdout);
n=gi(),m=gi();int x,y;
for(int i=1;i<=n;i++) v[i]=gi();
for(int i=1;i<=n;i++){
x=gi(),y=gi();
if(x!=0) lnk(x,y);
else root=y;
}
int block=sqrt(n);
if(n%block) cnt2=n/block+1;
else cnt2=n/block;
for(int i=1;i<=n;i++){
pos[i]=(i-1)/block+1;
kp[i]=(i-1)%block+1;
}
dfs(root,0);
make_tot1();make_tot2();make_tot3();int flag;
while(m--){
flag=gi();
if(flag==1){
x=gi(),y=gi()-v[x];
for(int i=dfn[x];i<=n&&pos[i]==pos[dfn[x]];i++) tot1[i]+=y;
for(int i=1;i<=cnt2;i++) tot2[i]+=(unsigned long long)1ll*num[i][x]*y;
for(int i=pos[dfn[x]];i<=cnt2;i++) tot3[i]+=y;
v[x]+=y;
}
else{
int l=gi(),r=gi();unsigned long long ans=0;
if(pos[l]==pos[r]){
for(int i=l;i<=r;i++)
ans+=query(end[i])-query(dfn[i]-1);
}
else{
for(int i=l;pos[i]==pos[l];i++) ans+=query(end[i])-query(dfn[i]-1);
for(int i=r;pos[i]==pos[r];i--) ans+=query(end[i])-query(dfn[i]-1);
for(int i=pos[l]+1;i<pos[r];i++) ans+=tot2[i];
}
printf("%llu\n",ans);
}
}
return 0;
}

bzoj 4765: 普通计算姬的更多相关文章

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

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

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

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

  3. bzoj 4765: 普通计算姬 主席树+替罪羊树思想

    题目大意: 给定一棵\(n\)个节点的带权树有根树,设\(sum_p\)表示以点\(p\)为根的这棵子树中所有节点的权 计算姬支持下列两种操作: 给定两个整数\(u,v\),修改点\(u\)的权值为\ ...

  4. bzoj 4765 普通计算姬(树状数组 + 分块)

    http://www.lydsy.com/JudgeOnline/problem.php?id=4765 很nice的一道题啊(可能是因为卡了n久终于做出来了 题意就是给你一棵带点权的有根树,sum( ...

  5. BZOJ 4765 普通计算姬 dfs序+分块+树状数组+好题!!!

    真是道好题...感到灵魂的升华... 按dfs序建树状数组,拿前缀和去求解散块: 按点的标号分块,分成一个个区间,记录区间子树和 的 总和... 具体地,需要记录每个点u修改后,对每一个块i的贡献,记 ...

  6. BZOJ 4765: 普通计算姬 [分块 树状数组 DFS序]

    传送门 题意: 一棵树,支持单点修改和询问以$[l,r]$为根的子树的权值和的和 只有我这种不会分块的沙茶不会做这道题吗? 说一点总结: 子树和当然上$dfs$序了,询问原序列一段区间所有子树和,对原 ...

  7. BZOJ 4765: 普通计算姬 (分块+树状数组)

    传送门 解题思路 树上的分块题,,对于修改操作,每次修改只会对他父亲到根这条链上的元素有影响:对于查询操作,每次查询[l,r]内所有元素的子树,所以就考虑dfn序,进标记一次,出标记一次,然后子树就是 ...

  8. bzoj 4766: 文艺计算姬 -- 快速乘

    4766: 文艺计算姬 Time Limit: 1 Sec  Memory Limit: 128 MB Description "奋战三星期,造台计算机".小W响应号召,花了三星期 ...

  9. BZOJ 4766: 文艺计算姬

    4766: 文艺计算姬 Time Limit: 1 Sec  Memory Limit: 128 MBSubmit: 456  Solved: 239[Submit][Status][Discuss] ...

随机推荐

  1. 对java多线程里Synchronized的思考

    Synchronized这个关键字在多线程里经常会出现,哪怕做到架构师级别了,在考虑并发分流时,也经常会用到它.在本文里,将通过一些代码实验来验证它究竟是"锁"什么. 在启动多个线 ...

  2. PHP入门怎么选?大学生适合学习吗?

    大学毕业,面对竞争激烈的社会,理想总是很丰满,现实却很残酷.在硕士.博士都随处可见的今天,本科和大专文凭就显得苍白无力,在面试官问你"有没有工作经验"的时候,你是不是只想起实习期间 ...

  3. JAVA8新特性(一)

    default拓展方法 java8为接口声明添加非抽象方法的实现,也成为拓展方法. public interface Formula { void doSomething(); default voi ...

  4. CCF-201509-3-生成模板系统

    问题描述 试题编号: 201509-3 试题名称: 模板生成系统 时间限制: 1.0s 内存限制: 256.0MB 问题描述: 问题描述 成成最近在搭建一个网站,其中一些页面的部分内容来自数据库中不同 ...

  5. thinkphp整合系列之极验滑动验证码

    对于建站的筒子们来说:垃圾广告真是让人深恶痛绝:为了清净:搞个难以识别的验证码吧:又被用户各种吐槽:直到后来出现了极验这个滑动的验证码:这真是一个体验好安全高的方案:官网:http://www.gee ...

  6. 一些内存模型、并发、netty知识点的记录

    happens-before:描述内存可见性as-if-serial:无论怎么重排序,程序的运行结果不会改变 ReentrantLock依赖了队列同步器AQS,其实现方式是volatile变量的读写操 ...

  7. java-8u151-64安装与配置环境变量

    去oracle官网下载 java jdk for developments(最新发布的java9与java8有很大差别,选择8就够用了) 我是装在默认的C盘里的,直接配置环境变量了 新建JAVA_HO ...

  8. 【JSOI2008】最大数

    https://www.luogu.org/problem/show?pid=1198 之前刚学完Splay想找题练手的时候做的,写完Splay交上去了才发现这应该是线段树裸题23333 Splay解 ...

  9. Codeforces 869E The Untended Antiquity

    题意:给定一个网格图,三种操作:1.在(r1,c1,r2,c2)处建围墙.2.删除(r1,c1,r2,c2)处的围墙.3.询问两点是否可达 思路比较巧妙,将围墙内的点赋加一个权值,询问的时候判断两个点 ...

  10. C++如何返回不定长数组

    起初遇到这个问题的时候便得知无法返回,那么为了达到相同的目的,该怎么办呢? 第一个想法便是 int * void() { int * want = new int[size]; //......do ...