BZOJ-4034 T2 树链剖分

4034: [HAOI2015]T2
Time Limit: 10 Sec Memory Limit: 256 MB
Submit: 1897 Solved: 615
[Submit][Status][Discuss]

Description
有一棵点数为 N 的树,以点 1 为根,且树点有边权。然后有 M 个
操作,分为三种:
操作 1 :把某个节点 x 的点权增加 a 。
操作 2 :把某个节点 x 为根的子树中所有点的点权都增加 a 。
操作 3 :询问某个节点 x 到根的路径中所有点的点权和。

Input
第一行包含两个整数 N, M 。表示点数和操作数。
接下来一行 N 个整数,表示树中节点的初始权值。
接下来 N-1 行每行三个正整数 fr, to , 表示该树中存在一条边 (fr, to) 。
再接下来 M 行,每行分别表示一次操作。其中第一个数表示该操
作的种类( 1-3 ) ,之后接这个操作的参数( x 或者 x a ) 。

Output
对于每个询问操作,输出该询问的答案。答案之间用换行隔开。

Sample Input
5 5
1 2 3 4 5
1 2
1 4
2 3
2 5
3 3
1 2 1
3 5
2 1 2
3 3

Sample Output
6
9
13

HINT
对于 100% 的数据, N,M<=100000 ,且所有输入数据的绝对值都不
会超过 10^6 。

Source
鸣谢bhiaibogf提供

题解:
树链剖分裸题,记录下每条链的长度即可,好久没打了,这个写的比较鬼畜….
开始出现了莫名的RE,真的是毫无道理的RE

code:

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
using namespace std;
long long read()
{
    long long x=0,f=1; char ch=getchar();
    while (ch<'0' || ch>'9') {if (ch=='-') f=-1; ch=getchar();}
    while (ch>='0' && ch<='9') {x=x*10+ch-'0'; ch=getchar();}
    return x*f;
}
#define maxn 200010
int n,m;
struct data{int next,to;}edge[maxn*2];
int head[maxn],cnt;long long va[maxn];
long long belong[maxn],size[maxn],deep[maxn],pl[maxn],sz,fa[maxn];
long long tree[maxn*4],del[maxn*4];
//---------------------------------------------------------------------
void add(int u,int v){cnt++;edge[cnt].to=v;edge[cnt].next=head[u];head[u]=cnt;}
void insert(int u,int v){add(u,v); add(v,u);}
//---------------------------------------------------------------------
void dfs_1(int now)
{
    size[now]=1;
    for (int i=head[now]; i; i=edge[i].next)
        if (edge[i].to!=fa[now])
            {
                fa[edge[i].to]=now; dfs_1(edge[i].to);
                size[now]+=size[edge[i].to];
                deep[now]=max(deep[now],deep[edge[i].to]);
            }
}
void dfs_2(int now,int chain)
{
    //printf("%d %d\n",now,chain);
    deep[now]=pl[now]=++sz; belong[now]=chain; int k=0;
    for (int i=head[now]; i; i=edge[i].next)
        if (edge[i].to!=fa[now] && size[k]<size[edge[i].to])
            k=edge[i].to;
    if (!k) return; dfs_2(k,chain);deep[now]=max(deep[now],deep[k]);
    for (int i=head[now]; i; i=edge[i].next)
        if (edge[i].to==fa[now] || edge[i].to==k) continue;
        else dfs_2(edge[i].to,edge[i].to),deep[now]=max(deep[now],deep[edge[i].to]);
}
//------------------------------------------------------------------------
inline void update(int now) {tree[now]=tree[now<<1]+tree[now<<1|1];}
inline void pushdown(int now,int l,int r)
{
    if (!del[now]) return;
    int mid=(l+r)>>1; int ln=mid-l+1,rn=r-mid;long long ad=0;
    ad=del[now],del[now]=0,del[now<<1]+=ad,del[now<<1|1]+=ad,
            tree[now<<1]+=ln*ad,tree[now<<1|1]+=rn*ad;
}
void segment_add(int now,int l,int r,int L,int R,long long val)
{
    pushdown(now,l,r);
    if (L<=l && R>=r) {del[now]+=val,tree[now]+=(r-l+1)*val;return;}
    int mid=(l+r)>>1;
    if (L<=mid) segment_add(now<<1,l,mid,L,R,val);
    if (R>mid) segment_add(now<<1|1,mid+1,r,L,R,val);
    update(now);
}
long long query(int now,int l,int r,int L,int R)
{
    pushdown(now,l,r);
    if (L<=l && R>=r) return tree[now];
    int mid=(l+r)>>1;long long ans=0;
    if (L<=mid) ans+=query(now<<1,l,mid,L,R);
    if (R>mid) ans+=query(now<<1|1,mid+1,r,L,R);
    return ans;
}
//-----------------------------------------------------------------------
void solvequery(int loc)
{
    long long ans=0;
    while (belong[loc]!=1)
        ans+=query(1,1,n,pl[belong[loc]],pl[loc]),loc=fa[belong[loc]];
    ans+=query(1,1,n,1,pl[loc]);
    printf("%lld\n",ans);
}
//------------------------------------------------------------------------
int main()
{
    n=read(),m=read();
    for (int i=1; i<=n; i++) va[i]=read();
    for (int u,v,i=1; i<=n-1; i++)
        u=read(),v=read(),insert(u,v);
    dfs_1(1); dfs_2(1,1);
//  for (int i=1; i<=n; i++) printf("%d ",pl[i]);puts("");
//  for (int i=1; i<=n; i++) printf("%d ",deep[i]);puts("");
//  for (int i=1; i<=n; i++) printf("%d ",belong[i]);puts("");
    for (int i=1; i<=n; i++)
        segment_add(1,1,n,pl[i],pl[i],va[i]);
    for (int i=1; i<=m; i++)
        {
            int opt=read(),x=read();long long a=0;
            if (opt==1) a=read(),segment_add(1,1,n,pl[x],pl[x],a);
            if (opt==2) a=read(),segment_add(1,1,n,pl[x],deep[x],a);
            if (opt==3) solvequery(x);
        }
    return 0;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值