码迷,mamicode.com
首页 > 其他好文 > 详细

BZOJ 4034 [HAOI2015]T2 树链剖分+线段树

时间:2015-09-28 10:07:26      阅读:175      评论:0      收藏:0      [点我收藏+]

标签:操作

题意:
一棵以1为根的树,有n个节点,m个操作。
第一种单点修改。
第二种修改一个点的子树。
第三种询问一个点到根的路径上所有点的权值和。
解析:
看到有人在做我就跑过来看了一下,看完题发现这不SB题么- -
于是就写了下,差点被出题人气死。
TMD 那个 fr , to 难道就是逗我玩的?
你丫fr,to不代表有向边?
这么出题不会掉RP?
改了20分钟就这错了?你逗我?
第一种操作略
第二种操作修改子树…dfs序。
第三种链剖完之后直接找就行了。
复杂度O(nlog^2n);
代码:

#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#define N 100100
#define lson l,mid,rt<<1
#define rson mid+1,r,rt<<1|1
using namespace std;
typedef long long ll;
int n,m,cnt,tot;
ll a[N],val[N];
int head[N];
int dep[N],son[N],fa[N],siz[N],tim[N],end[N],top[N];
struct node
{
    int from,to;
    int next;
}edge[N<<1];
void init()
{
    memset(head,-1,sizeof(head));
    cnt=1,dep[1]=1;
}
void edgeadd(int from,int to)
{
    edge[cnt].from=from,edge[cnt].to=to,edge[cnt].next=head[from];
    head[from]=cnt++;
}
void dfs1(int now)
{
    son[now]=-1,siz[now]=1;
    for(int i=head[now];i!=-1;i=edge[i].next)
    {
        int to=edge[i].to;
        if(to==fa[now])continue;
        fa[to]=now;
        dep[to]=dep[now]+1;
        dfs1(to);
        siz[now]+=siz[to];
        if(son[now]==-1||siz[son[now]]<siz[to])son[now]=to;
    }
}
void dfs2(int now,int tp)
{
    top[now]=tp,tim[now]=++tot;
    if(son[now]!=-1)dfs2(son[now],tp);
    for(int i=head[now];i!=-1;i=edge[i].next)
    {
        int to=edge[i].to;
        if(to==son[now]||to==fa[now])continue;
        dfs2(to,to);
    }
    end[now]=tot;
}

ll sum[N<<2],col[N<<2];
void pushup(int rt)
{
    sum[rt]=sum[rt<<1]+sum[rt<<1|1];
}
void pushdown(int rt,int l,int r)
{
    if(col[rt])
    {
        int mid=(l+r)>>1;
        sum[rt<<1]+=col[rt]*(ll)(mid-l+1);
        sum[rt<<1|1]+=col[rt]*(ll)(r-mid);
        col[rt<<1]+=col[rt];
        col[rt<<1|1]+=col[rt];
        col[rt]=0;
    }
}
void build(int l,int r,int rt)
{
    if(l==r)
    {
        sum[rt]=val[l];
        return;
    }
    int mid=(l+r)>>1;
    build(lson);
    build(rson);
    pushup(rt);
}
void update_pt(int p,ll v,int l,int r,int rt)
{
    if(l==r)
    {
        sum[rt]+=v;
        return;
    }
    int mid=(l+r)>>1;
    pushdown(rt,l,r);
    if(p<=mid)update_pt(p,v,lson);
    else update_pt(p,v,rson);
    pushup(rt);
}
void update_seg(ll v,int L,int R,int l,int r,int rt)
{
    if(L<=l&&r<=R)
    {
        col[rt]+=v;
        sum[rt]+=v*(ll)(r-l+1);
        return;
    }
    int mid=(l+r)>>1;
    pushdown(rt,l,r);
    if(L<=mid)update_seg(v,L,R,lson);
    if(R>mid)update_seg(v,L,R,rson);
    pushup(rt);
}
ll query_seg(int L,int R,int l,int r,int rt)
{
    ll ret=0;
    if(L<=l&&r<=R)
    {
        return sum[rt];
    }
    int mid=(l+r)>>1;
    pushdown(rt,l,r);
    if(L<=mid)ret+=query_seg(L,R,lson);
    if(R>mid)ret+=query_seg(L,R,rson);
    return ret;
}
ll query(int x)
{
    ll ret=0;
    while(top[x])
    {
        int l=tim[top[x]],r=tim[x];
        ret+=query_seg(l,r,1,n,1);
        x=fa[top[x]];
    }
    return ret;
}
int main()
{
    init();
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;i++)scanf("%lld",&a[i]);
    for(int i=1;i<n;i++)
    {
        int x,y;
        scanf("%d%d",&x,&y);
        edgeadd(x,y);
        edgeadd(y,x);
    }
    dfs1(1);
    dfs2(1,1);
    for(int i=1;i<=n;i++)val[tim[i]]=a[i];
    build(1,n,1);
    for(int i=1;i<=m;i++)
    {
        int opt,x;
        ll a;
        scanf("%d",&opt);
        if(opt==1)
        {
            scanf("%d%lld",&x,&a);
            update_pt(tim[x],a,1,n,1);
        }else if(opt==2)
        {
            scanf("%d%lld",&x,&a);
            update_seg(a,tim[x],end[x],1,n,1);
        }else
        {
            scanf("%d",&x);
            printf("%lld\n",query(x));
        }
    }
}

版权声明:本文为博主原创文章,未经博主允许不得转载。

BZOJ 4034 [HAOI2015]T2 树链剖分+线段树

标签:操作

原文地址:http://blog.csdn.net/wzq_qwq/article/details/48780369

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!