[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并不知道它的答案是否正确,你能帮助他吗?

Solution

分块。块内直接统计,单点的sum树状数组暴力加起来

为了方便修改,g[a][i]表示点a对块[i]的贡献

另外,好坑啊这题会爆long long

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<cmath>
#define MAXN 100007
using namespace std;
typedef unsigned long long LL;
int n,m,init,num,head[MAXN],g[MAXN][330],cnt=0;
LL c[MAXN],d[MAXN],sum[MAXN],blocks[330];
int dfn_clock=0,in[MAXN],out[MAXN],a[MAXN];
LL read()
{
    LL x=0,f=1;char c=getchar();
    while(c<'0'||c>'9'){
        if(c=='-')f=-1;c=getchar();
    }
    while(c>='0'&&c<='9'){
        x=x*10+c-'0';c=getchar();
    }
    return x*f;
}
struct Node
{
    int next,to;
}Edges[MAXN*2];
void addedge(int u,int v)
{
    Edges[++cnt].next=head[u];
    head[u]=cnt;
    Edges[cnt].to=v;
}
int lowbit(int x){return x&-x;}
void add(int pos,int x)
{
    while(pos<=n)
    {
        c[pos]+=x;
        pos+=lowbit(pos);
    }
}
LL query(int pos)
{
    LL res=0;
    while(pos>0)
    {
        res+=c[pos];
        pos-=lowbit(pos);
    }
    return res;
}
void dfs(int u,int f)
{
    dfn_clock++;in[u]=dfn_clock;
    sum[u]=d[u];
    a[(u-1)/init]++;
    for(int i=0;i<num;i++)
    g[u][i]+=a[i];
    for(int i=head[u];~i;i=Edges[i].next)
    {
        int v=Edges[i].to;
        if(v==f)continue;
        dfs(v,u);
        sum[u]+=sum[v];
    }
    blocks[(u-1)/init]+=sum[u];
    out[u]=dfn_clock;
    a[(u-1)/init]--;
}
void Change(int a,int b)
{
    add(in[a],b-d[a]);
    for(int i=0;i<num;i++)
    blocks[i]+=(b-d[a])*g[a][i];
    d[a]=b;
}
void Query(int a,int b)
{
    LL res=0;
    if((a-1)/init==(b-1)/init)
    for(int i=a;i<=b;i++)
    res+=query(out[i])-query(in[i]-1);
    else 
    {
        for(int i=(a-1)/init+1;i<=(b-1)/init-1;i++)
        res+=blocks[i];
        for(int i=a;i<((a-1)/init+1)*init+1;i++)
        res+=query(out[i])-query(in[i]-1);
        for(int i=b;i>=((b-1)/init)*init+1;i--)
        res+=query(out[i])-query(in[i]-1);
    }
    printf("%llu\n",res);
}
int main()
{
    memset(head,-1,sizeof(head));
    n=read(),m=read();
    init=(int)sqrt(n+0.1);
    num=(n-1)/init+1;
    for(int i=1;i<=n;i++)
    d[i]=read();
    int root;
    for(int i=1;i<=n;i++)
    {
        int u=read(),v=read();
        if(!u){root=v;continue;}
        addedge(u,v);
        addedge(v,u);
    }
    dfs(root,0);
    for(int i=1;i<=n;i++)
    add(in[i],d[i]);
    for(int i=1;i<=m;i++)
    {
        int opt=read(),a=read();LL b=read();
        if(opt==1)Change(a,b);
        else Query(a,b);
    }
    return 0;
}

 

posted @ 2017-05-15 16:32  Zars19  阅读(216)  评论(0编辑  收藏  举报