4034: [HAOI2015]T2 (树链剖分)

来源:互联网 发布:openwrt端口转发 编辑:程序博客网 时间:2024/04/30 13:03

树链剖分+线段树区间更新和区间求和。

注意,一个子树的所有点上的序号在线段树上的位置是连续的,意识到这点这个题就是模版题了。

另外关于树链剖分的细节,第二次递归的时候要先计算重边对应结点否则会出错。

线段树中,push_down的部分注意可能溢出int。最终答案要用longlong。

#include<iostream>#include<cstdio>#include<cstring>#include<vector>#include<cmath>#include<map>#include<string>#include<set>#include<queue>#include<algorithm>using namespace std;typedef long long LL;const int maxn=100010;int n;int arr[maxn];LL sum[4*maxn],tar[4*maxn];int head[maxn],to[maxn*2],nxt[maxn*2],edge;int siz[maxn],son[maxn],fa[maxn],top[maxn],dep[maxn],id[maxn],rid[maxn],tot;int eid[maxn];void init(){    tot=0;    memset(son,-1,sizeof(son));    edge=0;    memset(head,-1,sizeof(head));}void addEdge(int u,int v){    to[edge]=v,nxt[edge]=head[u],head[u]=edge++;    to[edge]=u,nxt[edge]=head[v],head[v]=edge++;}void dfs1(int now,int f,int d){    siz[now]=1;    dep[now]=d;    fa[now]=f;    for(int i=head[now]; i!=-1; i=nxt[i])    {        int v=to[i];        if(v!=f)        {            dfs1(v,now,d+1);            if(son[now]==-1||siz[son[now]]<siz[v])                son[now]=v;            siz[now]+=siz[v];        }    }}void dfs2(int now,int tp){    id[now]=++tot;    rid[id[now]]=now;    top[now]=tp;    if(son[now]!=-1)        dfs2(son[now],tp);    for(int i=head[now]; i!=-1; i=nxt[i])    {        int v=to[i];        if(v!=fa[now]&&v!=son[now])        {            dfs2(v,v);        }    }    eid[now]=tot;}void push_up(int o){    sum[o]=sum[o<<1]+sum[o<<1|1];}void push_down(int o,int m){    if(tar[o])    {        tar[o<<1]+=tar[o];        tar[o<<1|1]+=tar[o];        sum[o<<1]+=tar[o]*(m-m/2);        sum[o<<1|1]+=tar[o]*(m/2);        tar[o]=0;    }}void Add(int o,int l,int r,LL val,int ql,int qr){    if(ql<=l&&r<=qr)    {        sum[o]+=(r-l+1)*val;        tar[o]+=val;    }    else    {        push_down(o,r-l+1);        int m=l+(r-l)/2;        if(ql<=m)            Add(o<<1,l,m,val,ql,qr);        if(m<qr)            Add(o<<1|1,m+1,r,val,ql,qr);        push_up(o);    }}LL querySum(int o,int l,int r,int ql,int qr){    if(ql<=l&&r<=qr)        return sum[o];    else    {        push_down(o,r-l+1);        int m=l+(r-l)/2;        LL s=0;        if(ql<=m)            s+=querySum(o<<1,l,m,ql,qr);        if(m<qr)            s+=querySum(o<<1|1,m+1,r,ql,qr);        return s;    }}void build(int o,int l,int r){    tar[o]=0;    if(l==r)    {        sum[o]=arr[rid[l]];    }    else    {        int m=l+(r-l)/2;        build(o<<1,l,m);        build(o<<1|1,m+1,r);        push_up(o);    }}LL getSum(int x,int y){    LL s=0;    while(top[x]!=top[y])    {        if(dep[top[x]]>dep[top[y]])            swap(x,y);        s+=querySum(1,1,n,id[top[y]],id[y]);        y=fa[top[y]];    }    if(dep[x]>dep[y])        swap(x,y);    s+=querySum(1,1,n,id[x],id[y]);    return s;}int main(){    int m;    scanf("%d%d",&n,&m);    init();    for(int i=1; i<=n; ++i)        scanf("%d",&arr[i]);    for(int i=1; i<n; ++i)    {        int a,b;        scanf("%d%d",&a,&b);        addEdge(a,b);    }    dfs1(1,-1,1);    dfs2(1,1);    build(1,1,n);    while(m--)    {        int x,a,b;        scanf("%d",&x);        if(x==1)        {            scanf("%d%d",&a,&b);            Add(1,1,n,b,id[a],id[a]);        }        else if(x==2)        {            scanf("%d%d",&a,&b);            Add(1,1,n,b,id[a],eid[a]);        }        else if(x==3)        {            scanf("%d",&a);            printf("%lld\n",getSum(1,a));        }    }    return 0;}


0 0
原创粉丝点击