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 long
using 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;
}

2018.06.30 BZOJ4765: 普通计算姬(dfs序+分块+树状数组)的更多相关文章

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

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

  2. BZOJ 2819: Nim dfs序维护树状数组,倍增

    1.随机选两个堆v,u,询问若在v到u间的路径上的石子堆中玩Nim游戏,是否有必胜策略,如果有,vfleaking将会考虑将这些石子堆作为初始局面之一,用来坑玩家.2.把堆v中的石子数变为k. 分析: ...

  3. BZOJ 4999: This Problem Is Too Simple! DFS序+LCA+树状数组+离线

    Code: #include<bits/stdc++.h> #define setIO(s) freopen(s".in","r",stdin) , ...

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

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

  5. 2018.09.30 bzoj3551:Peaks加强版(dfs序+主席树+倍增+kruskal重构树)

    传送门 一道考察比较全面的题. 这道题又用到了熟悉的kruskal+倍增来查找询问区间的方法. 查到询问的子树之后就可以用dfs序+主席树统计答案了. 代码: #include<bits/std ...

  6. BZOJ 1103: [POI2007]大都市meg(dfs序,树状数组)

    本来还想链剖的,结果才发现能直接树状数组的= = 记录遍历到达点与退出点的时间,然后一开始每个到达时间+1,退出时间-1,置为公路就-1,+1,询问直接点1到该点到达时间求和就行了- - CODE: ...

  7. HDU 6203 ping ping ping(dfs序+LCA+树状数组)

    http://acm.hdu.edu.cn/showproblem.php?pid=6203 题意: n+1 个点 n 条边的树(点标号 0 ~ n),有若干个点无法通行,导致 p 组 U V 无法连 ...

  8. POJ 2763 Housewife Wind(DFS序+LCA+树状数组)

    Housewife Wind Time Limit: 4000MS   Memory Limit: 65536K Total Submissions: 11419   Accepted: 3140 D ...

  9. 【Tyvj2133&BZOJ1146】网络管理Network(树套树,DFS序,树状数组,主席树,树上差分)

    题意:有一棵N个点的树,每个点有一个点权a[i],要求在线实现以下操作: 1:将X号点的点权修改为Y 2:查询X到Y的路径上第K大的点权 n,q<=80000 a[i]<=10^8 思路: ...

随机推荐

  1. node 把前台传来的base64码转成图片存放

    最近做个人网站头像修改用到了,在做头像修改,先做了一个图片切割,只需要上传你选中部分, 如图 这种需求 应该还是会遇到的, http://pan.baidu.com/s/1boVkn1t 这是裁剪图片 ...

  2. 突破MSDE 的2GB数据限制

    Windows Registry Editor Version 5.00 [HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\MSSQLServer\MSSQLServer\ ...

  3. libcurl 不支持https访问

    项目中使用libcurl 访问https的时候会报错,比如:“Unsupported protocol” 或者:“Protocol https not supported or disabled in ...

  4. UI5-文档-4.14-Custom CSS and Theme Colors

    有时我们需要定义一些更细粒度的布局,这时我们可以通过向控件添加自定义样式类来使用CSS的灵活性,并根据自己的喜好对它们进行样式化. Preview The space between the butt ...

  5. js脚本代码调试小技巧

    以前写js代码调试代码查看数据是否正确的时候不知道F12(开发者工具),都是alert(xxx)或者console.log(xxx), 现在知道还可以用document.write或者try...ca ...

  6. jquery实现背景图片动态适应

    背景 在我的一个项目中用到了背景图片,发现其中有一个问题,当页面长度动态变化时,原来能占满全部内容背景的图片会变得不能占满全部背景.如下图的效果: 这是正常的,背景图片占满全屏 当页面内容变长出现了滚 ...

  7. 转。。原理同样支持 delphi

    我用C#导出excel 带图片,用office2003 正常,但换成office 2007 时,我指定多个单元格分别插入图片,这个图片不在此单元格内,这些图片全都集中在一起,在一个位置上.很奇怪,看起 ...

  8. C#累加器函数Aggregate用法 讲解

    Enumerable.Aggregate 扩展方法在System.Linq命名空间中,是Enumerable类的第一个方法(按字母顺序排名),但确是Enumerable里面相对复杂的方法. MSDN对 ...

  9. 吴裕雄 数据挖掘与分析案例实战(10)——KNN模型的应用

    # 导入第三方包import pandas as pd # 导入数据Knowledge = pd.read_excel(r'F:\\python_Data_analysis_and_mining\\1 ...

  10. 使用git提交代码到GitHub

    0.下载Git Bash,在Windows系统可以用Git Bash通过简单的命令将代码提交到GitHub1.打开项目所在的文件夹,右键,"Git Bash Here"2.初次使用 ...