首页 技术 正文
技术 2022年11月12日
0 收藏 613 点赞 2,378 浏览 2640 个字

4765: 普通计算姬

Time Limit: 30 Sec Memory Limit: 256 MB

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<=105,M<=105

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


这是一道不那么简单的的数据结构题,我们先把问题简化,如何维护动态子树和?

显然用树剖+树状数组或者dfsdfsdfs序+树状数组维护。

回到这道题上来:动态维护子树和的和?树套树剖?显然不可做也不够优秀,那么我们该用什么玄学做法呢?。

让我们冷静思考一下……

咦,原来修改一个树上的节点只会影响把以从它到根节点的路径上出现的节点作为根的子树和。那这些节点能不能与处理出来呢?好像空间炸了。

唔,等等!!!假如我们不预处理,那么单次查询 O(nlogn)O(nlogn)O(nlogn),如果我们O(n2)O(n^2)O(n2)预处理,那么单次查询O(logn)O(logn)O(logn),如果我们对树分块,O(nsqrt(n))O(n sqrt(n))O(nsqrt(n))预处理,能不能使单词查询O(logn∗sqrt(n))O(logn*sqrt(n))O(logn∗sqrt(n))呢?如果我们在块内维护子树的权值和,貌似是可以的啊。

那么这道题的思路就出来了,预处理出每个节点对每个块的贡献,然后直接更新和查询即可,注意开unsignedunsignedunsigned longlonglong longlonglong,不然会爆炸。

代码如下:

#include<bits/stdc++.h>#define N 100005#define K 350#define ll unsigned long longusing namespace std;int root,tot=0,g[N][K],in[N],out[N],bl[N],first[N],siz[N],dfn=0,n,m,sig,cnt[N],len;ll d[N],sum[N],q[N],bit[N];struct Node{int v,next;}e[N<<1];inline ll read(){    ll ans=0;    char ch=getchar();    while(!isdigit(ch))ch=getchar();    while(isdigit(ch))ans=(ans<<3)+(ans<<1)+ch-'0',ch=getchar();    return ans;}inline int lowbit(int x){return x&-x;}inline ll query(int x){ll ans=0;for(int i=x;i;i-=lowbit(i))ans+=bit[i];return ans;}inline void update(int x,long long v){for(int i=x;i<=n;i+=lowbit(i))bit[i]+=v;}inline void add(int u,int v){e[++tot].v=v,e[tot].next=first[u],first[u]=tot;}inline void dfs(int p,int fa){    in[p]=++dfn,update(in[p],d[p]),++cnt[bl[p]];    for(int i=1;i<=sig;++i)g[p][i]=cnt[i];    sum[p]=d[p];    for(int i=first[p];i;i=e[i].next){        int v=e[i].v;        if(v==fa)continue;        dfs(v,p);        sum[p]+=sum[v];    }    out[p]=dfn;    --cnt[bl[p]];    q[bl[p]]+=sum[p];}int main(){    n=read(),m=read(),len=sqrt(n);    for(int i=1;i<=n;++i)d[i]=read(),bl[i]=(i-1)/len+1;    sig=bl[n];    for(int i=1;i<=n;++i){        int u=read(),v=read();        if(!u)root=v;        else add(u,v),add(v,u);    }    dfs(root,root);    while(m--){        int op=read(),u=read(),v=read();        if(op==1){            for(int i=1;i<=sig;++i)q[i]+=g[u][i]*(v-d[u]);            update(in[u],v-d[u]),d[u]=v;            continue;        }        ll ans=0;        if(bl[u]==bl[v])for(int i=u;i<=v;++i)ans+=query(out[i])-query(in[i]-1);        else{            for(int i=bl[u]+1;i<=bl[v]-1;++i)ans+=q[i];            for(int i=u;bl[u]==bl[i];++i)ans+=query(out[i])-query(in[i]-1);            for(int i=v;bl[v]==bl[i];--i)ans+=query(out[i])-query(in[i]-1);        }        printf("%llu\n",ans);    }    return 0;}
相关推荐
python开发_常用的python模块及安装方法
adodb:我们领导推荐的数据库连接组件bsddb3:BerkeleyDB的连接组件Cheetah-1.0:我比较喜欢这个版本的cheeta…
日期:2022-11-24 点赞:878 阅读:9,491
Educational Codeforces Round 11 C. Hard Process 二分
C. Hard Process题目连接:http://www.codeforces.com/contest/660/problem/CDes…
日期:2022-11-24 点赞:807 阅读:5,907
下载Ubuntn 17.04 内核源代码
zengkefu@server1:/usr/src$ uname -aLinux server1 4.10.0-19-generic #21…
日期:2022-11-24 点赞:569 阅读:6,740
可用Active Desktop Calendar V7.86 注册码序列号
可用Active Desktop Calendar V7.86 注册码序列号Name: www.greendown.cn Code: &nb…
日期:2022-11-24 点赞:733 阅读:6,492
Android调用系统相机、自定义相机、处理大图片
Android调用系统相机和自定义相机实例本博文主要是介绍了android上使用相机进行拍照并显示的两种方式,并且由于涉及到要把拍到的照片显…
日期:2022-11-24 点赞:512 阅读:8,132
Struts的使用
一、Struts2的获取  Struts的官方网站为:http://struts.apache.org/  下载完Struts2的jar包,…
日期:2022-11-24 点赞:671 阅读:5,293