首页 > 代码库 > BZOJ4034 树上操作(树剖 线段树大模板)

BZOJ4034 树上操作(树剖 线段树大模板)

BZOJ4034

long long 是大坑点

貌似long long 跟int 乘起来会搞事情?...

A了这题线段树和树剖的基础OK 

嘛 重点过掉的还是线段树区间更新的lazy tag吧

 

#include<cstdio>
#include<cstring>
#define N 100001
using namespace std;

struct ed{
    int nxt,to;
}e[N*2];
int ne=0,head[N];
long long int w0[N];

struct t{
    int l,r;
    long long sum,add;
}tree[N*4];
int father[N],son[N],hson[N],id[N],reid[N],top[N],cnt=0;
int deep[N];
int n,m;

void init1(int cur,int fat,int d)
{
    deep[cur]=d;
    father[cur]=fat;
    son[cur]=0;
    
    for(int i=head[cur];i;i=e[i].nxt)
    {
        int v=e[i].to;
        if(v==fat) continue;
        init1(v,cur,d+1);
        son[cur]+=1+son[v];
        if(son[v]>=son[hson[cur]]) hson[cur]=v;
    }
}

void init2(int cur,int up)
{
    id[cur]=++cnt;
    reid[cnt]=cur;
    top[cur]=up;
    
    if(hson[cur])
        init2(hson[cur],up);
    
    for(int i=head[cur];i;i=e[i].nxt)
    {
        int v=e[i].to;
        if(v==hson[cur]||v==father[cur]) continue;
        init2(v,v);
    }
}

void build(int L,int R,int node)
{
    tree[node].l=L;
    tree[node].r=R;
    
    if(L==R)
    {
        tree[node].sum=w0[reid[L]];
        return ;
    }
    
    int mid=(L+R)>>1;
    
    build(L,mid,node*2);
    build(mid+1,R,node*2+1);
    
    tree[node].sum=tree[node*2].sum+tree[node*2+1].sum;
}

void pushdown(int node)
{
    long long int k=tree[node].add;
    tree[node].add=0;
    node=node*2;
    
    
    tree[node].add+=k;
    tree[node+1].add+=k;
    tree[node].sum+=k*(tree[node].r-tree[node].l+1);
    tree[node+1].sum+=k*(tree[node+1].r-tree[node+1].l+1);
}

void update(int L,int R,long long int val,int node)
{
    if(L>tree[node].r || R<tree[node].l) return; 
    
    if(L<=tree[node].l && R>=tree[node].r)
    {
        tree[node].sum+=(tree[node].r-tree[node].l+1)*val;
        tree[node].add+=val;
        return;
    }
    
    if(tree[node].add) pushdown(node);
    update(L,R,val,node*2);
    update(L,R,val,node*2+1);
    tree[node].sum=tree[node*2].sum+tree[node*2+1].sum;
}

long long int getsum(int L,int R,int node)
{
    if(L>tree[node].r || R<tree[node].l) return 0;
    
    if(L<=tree[node].l && R>=tree[node].r)
        return tree[node].sum;
        
    pushdown(node);
    return getsum(L,R,node*2)+getsum(L,R,node*2+1);
}

long long int Qsum(int v)
{
    long long int ans=0;
    while(top[v]!=1)
    {
        ans+=getsum(id[top[v]],id[v],1);
        v=father[top[v]];
    }
    
    ans+=getsum(1,id[v],1);
    
    return ans;
}

void ade(int from,int to)
{
    e[++ne].nxt=head[from];
    head[from]=ne;
    e[ne].to=to;
}

int main()
{
    scanf("%d %d",&n,&m);
 
     memset(tree,0,sizeof(tree));
    
    for(int i=1;i<=n;i++)
        scanf("%lld",&w0[i]);
        
    for(int i=1;i<n;i++)
    {
        int a,b;
        scanf("%d %d",&a,&b);
        ade(a,b);
        ade(b,a);
    }
    
    init1(1,0,1);
    init2(1,1);
    build(1,cnt,1);
    

    for(int i=1;i<=m;i++)
    {
        int flag;
        scanf("%d",&flag);
        
        if(flag==1)
        {
            int pt;
            long long val;//val这里是大迷点
            scanf("%d %lld",&pt,&val);
            update(id[pt],id[pt],val,1);
        }
        else if(flag==2)
        {
            int root;
            long long int val;
            scanf("%d %lld",&root,&val);
            update(id[root],id[root]+son[root],val,1);
        }
        else
        {
            int v;
            scanf("%d",&v);
            printf("%lld\n",Qsum(v));
        }
    }
    
    return 0;
}

 

BZOJ4034 树上操作(树剖 线段树大模板)