树链剖分小结板子

来源:互联网 发布:淘宝卖家报复的买家 编辑:程序博客网 时间:2024/05/22 04:45

题目链接:树的统计Count

树链剖分(权值在点上)[单点修改 询问区间和/最大值]:

int a[30005];struct node{    int tl,tr,maxx,sum;    node():maxx(0),sum(0) {}} tree[120020];void pushup(int id){    tree[id].sum=tree[id<<1].sum+tree[id<<1|1].sum;    tree[id].maxx=max(tree[id<<1].maxx,tree[id<<1|1].maxx);}void build(int id,int tl,int tr){    tree[id].tl=tl,tree[id].tr=tr;    if(tl==tr)    {        tree[id].maxx=a[tl];        tree[id].sum=a[tl];    }    else    {        int tm=(tl+tr)>>1;        build(id<<1,tl,tm);        build(id<<1|1,tm+1,tr);        pushup(id);    }}void update(int id,int wz,int val){    int tl=tree[id].tl,tr=tree[id].tr;    if(tl==wz && wz==tr)    {        tree[id].maxx=val;        tree[id].sum=val;    }    else    {        int tm=(tl+tr)>>1;        if(tm>=wz)update(id<<1,wz,val);        else update(id<<1|1,wz,val);        pushup(id);    }}int get_max(int id,int ql,int qr){    int tl=tree[id].tl,tr=tree[id].tr;    if(ql<=tl && tr<=qr)return tree[id].maxx;    int tm=(tl+tr)>>1,res1=-inf,res2=-inf;    if(tm>=ql)res1=get_max(id<<1,ql,qr);    if(tm<qr)res2=get_max(id<<1|1,ql,qr);    return max(res1,res2);}int get_sum(int id,int ql,int qr){    int tl=tree[id].tl,tr=tree[id].tr;    if(ql<=tl && tr<=qr)return tree[id].sum;    int tm=(tl+tr)>>1;    int sum=0;    if(tm>=ql)sum+=get_sum(id<<1,ql,qr);    if(tm<qr)sum+=get_sum(id<<1|1,ql,qr);    return sum;}int pre[30005],siz[30005],dep[30005];int top[30005],node_id[30005],heavy[30005];int val[30005],idx=1;vector<int>G[30005];int dfs(int x,int fa,int depth){    dep[x]=depth,pre[x]=fa;    int res=1,maxx=0;    int len=G[x].size();    for(int i=0; i<len; i++)    {        if(G[x][i]==fa)continue;        int t=dfs(G[x][i],x,depth+1);        if(t>maxx)maxx=t,heavy[x]=G[x][i];        res+=t;    }    return siz[x]=res;}void slpf(int x,int fa,int tp){    node_id[x]=idx++;    top[x]=tp;    int len=G[x].size();    if(heavy[x])slpf(heavy[x],x,tp);    for(int i=0; i<len; i++)    {        int nex=G[x][i];        if(nex==fa)continue;        if(nex!=heavy[x])slpf(nex,x,nex);    }}int getmax(int x,int y){    int ans=-inf,res;    while(top[x]!=top[y])    {        if(dep[top[x]]>dep[top[y]])        {            res=get_max(1,node_id[top[x]],node_id[x]);            x=pre[top[x]];        }        else        {            res=get_max(1,node_id[top[y]],node_id[y]);            y=pre[top[y]];        }        if(res>ans)ans=res;    }    if(dep[x]>dep[y])swap(x,y);    res=get_max(1,node_id[x],node_id[y]);    if(res>ans)ans=res;    return ans;}int getsum(int x,int y){    int ans=0,res;    while(top[x]!=top[y])    {        if(dep[top[x]]>dep[top[y]])        {            res=get_sum(1,node_id[top[x]],node_id[x]);            x=pre[top[x]];        }        else        {            res=get_sum(1,node_id[top[y]],node_id[y]);            y=pre[top[y]];        }        ans+=res;    }    if(dep[x]>dep[y])swap(x,y);    res=get_sum(1,node_id[x],node_id[y]);    ans+=res;    return ans;}int main(){    int n;    scanf("%d",&n);    for(int i=1; i<=n-1; i++)    {        int x,y;        scanf("%d%d",&x,&y);        G[x].push_back(y);        G[y].push_back(x);    }    dfs(1,0,1);    slpf(1,0,1);    for(int i=1; i<=n; i++)        scanf("%d",&a[node_id[i]]);    build(1,1,n);    int q;    scanf("%d",&q);    while(q--)    {        char op[10];        int x,y;        scanf("%s%d%d",op,&x,&y);        if(op[0]=='Q' && op[1]=='M')            printf("%d\n",getmax(x,y));        if(op[0]=='Q' && op[1]=='S')            printf("%d\n",getsum(x,y));        if(op[0]=='C')update(1,node_id[x],y);    }    return 0;}

题目链接:树上操作

树链剖分(权值在点上)[单点/区间修改 询问区间和]:

struct node{    int tl,tr;    ll lazy,sum;    node():lazy(0),sum(0) {}}tree[400020];int a[100005];void pushup(int id){    tree[id].sum=tree[id<<1].sum+tree[id<<1|1].sum;}void build(int id,int tl,int tr){    tree[id].tl=tl,tree[id].tr=tr;    tree[id].lazy=tree[id].sum=0;    if(tl==tr)tree[id].sum=(ll)a[tl];    else    {        int tm=(tr+tl)>>1;        build(id<<1,tl,tm);        build(id<<1|1,tm+1,tr);        pushup(id);    }}void pushdown(int id){    if(!tree[id].lazy)return;    tree[id<<1].lazy+=tree[id].lazy;    tree[id<<1|1].lazy+=tree[id].lazy;    tree[id<<1].sum+=(tree[id<<1].tr-tree[id<<1].tl+1)*tree[id].lazy;    tree[id<<1|1].sum+=(tree[id<<1|1].tr-tree[id<<1|1].tl+1)*tree[id].lazy;    tree[id].lazy=0;}void update(int id,int ql,int qr,ll val){    int tl=tree[id].tl,tr=tree[id].tr;    if(ql>tr || qr<tl)return;    if(ql<=tl && tr<=qr)    {        tree[id].lazy+=val;        tree[id].sum+=(tr-tl+1)*val;        return;    }    pushdown(id);    update(id<<1,ql,qr,val);    update(id<<1|1,ql,qr,val);    pushup(id);}ll get_sum(int id,int ql,int qr){    int tl=tree[id].tl,tr=tree[id].tr;    if(ql>tr || qr<tl)return 0;    if(ql<=tl && tr<=qr)return tree[id].sum;    ll ans=0;    pushdown(id);    ans+=get_sum(id<<1,ql,qr);    ans+=get_sum(id<<1|1,ql,qr);    pushup(id);    return ans;}int pre[100005],siz[100005],dep[100005];int top[100005],node_id[100005],heavy[100005];int val[100005],lson[100005],rson[100005],idx=0;vector<int>G[100005];int dfs(int x,int fa,int depth){    dep[x]=depth,pre[x]=fa;    int res=1,maxx=0;    int len=G[x].size();    for(int i=0; i<len; i++)    {        if(G[x][i]==fa)continue;        int t=dfs(G[x][i],x,depth+1);        if(t>maxx)maxx=t,heavy[x]=G[x][i];        res+=t;    }    return siz[x]=res;}void slpf(int x,int fa,int tp){    lson[x]=node_id[x]=++idx;    top[x]=tp;    int len=G[x].size();    if(heavy[x])slpf(heavy[x],x,tp);    for(int i=0; i<len; i++)    {        int nex=G[x][i];        if(nex==fa)continue;        if(nex!=heavy[x])slpf(nex,x,nex);    }    rson[x]=idx;}ll getsum(int x,int y){    ll ans=0,res;    while(top[x]!=top[y])    {        if(dep[top[x]]>dep[top[y]])        {            res=get_sum(1,node_id[top[x]],node_id[x]);            x=pre[top[x]];        }        else        {            res=get_sum(1,node_id[top[y]],node_id[y]);            y=pre[top[y]];        }        ans+=res;    }    if(dep[x]>dep[y])swap(x,y);    res=get_sum(1,node_id[x],node_id[y]);    ans+=res;    return ans;}int main(){    int n,q;    scanf("%d%d",&n,&q);    for(int i=1;i<=n;i++)        scanf("%d",&val[i]);    for(int i=1;i<=n-1;i++)    {        int x,y;        scanf("%d%d",&x,&y);        G[x].push_back(y);        G[y].push_back(x);    }    dfs(1,0,1);    slpf(1,0,1);    for(int i=1;i<=n;i++)        a[node_id[i]]=val[i];    build(1,1,n);    while(q--)    {        int op,x;ll y;        scanf("%d",&op);        if(op==1)        {            scanf("%d%lld",&x,&y);            update(1,node_id[x],node_id[x],y);        }        if(op==2)        {            scanf("%d%lld",&x,&y);            update(1,lson[x],rson[x],y);        }        if(op==3)        {            scanf("%d",&x);            printf("%lld\n",getsum(1,x));        }    }    return 0;}

题目链接:Query on a tree

树链剖分(权值在边上)[单点修改 询问区间最大值]:

int a[10005];struct node{    int tl,tr,val;} tree[40020];void pushup(int id){    tree[id].val=max(tree[id<<1].val,tree[id<<1|1].val);}void build(int id,int tl,int tr){    tree[id].tl=tl,tree[id].tr=tr;    if(tl==tr)tree[id].val=a[tl];    else    {        int tm=(tl+tr)>>1;        build(id<<1,tl,tm);        build(id<<1|1,tm+1,tr);        pushup(id);    }}void update(int id,int wz,int val){    int tl=tree[id].tl,tr=tree[id].tr;    if(tl==wz && wz==tr)tree[id].val=val;    else    {        int tm=(tl+tr)>>1;        if(tm>=wz)update(id<<1,wz,val);        else update(id<<1|1,wz,val);        pushup(id);    }}int getval(int id,int ql,int qr){    int tl=tree[id].tl,tr=tree[id].tr;    if(ql<=tl && tr<=qr)return tree[id].val;    int tm=(tl+tr)>>1,res1=0,res2=0;    if(tm>=ql)res1=getval(id<<1,ql,qr);    if(tm<qr)res2=getval(id<<1|1,ql,qr);    return max(res1,res2);}struct edge{    int nex,id,val;    edge(int nex,int id,int val):        nex(nex),id(id),val(val) {}};int pre[10005],siz[10005],dep[10005];int top[10005],edge_id[10005],heavy[10005];int val[10005],ith[10005];int idx=1;vector<edge>G[10005];void init(void){    idx=1;    memset(a,0,sizeof(a));    memset(ith,0,sizeof(ith));    memset(val,0,sizeof(val));    memset(top,0,sizeof(top));    memset(pre,0,sizeof(pre));    memset(siz,0,sizeof(siz));    memset(dep,0,sizeof(dep));    memset(heavy,0,sizeof(heavy));    memset(tree,0,sizeof(tree));    memset(edge_id,0,sizeof(edge_id));}int dfs(int x,int fa,int depth){    dep[x]=depth,pre[x]=fa;    int res=1,maxx=0;    int len=G[x].size();    for(int i=0; i<len; i++)    {        int nex=G[x][i].nex;        if(nex==fa)continue;        int t=dfs(nex,x,depth+1);        ith[G[x][i].id]=nex;        val[nex]=G[x][i].val;        if(t>maxx)            maxx=t,heavy[x]=nex;        res+=t;    }    return siz[x]=res;}void slpf(int x,int fa,int tp){    int len=G[x].size();    if(pre[x])edge_id[x]=idx++;    top[x]=tp;    if(heavy[x])slpf(heavy[x],x,tp);    for(int i=0; i<len; i++)    {        int nex=G[x][i].nex;        if(nex==fa)continue;        if(nex!=heavy[x])            slpf(nex,x,nex);    }}int getmax(int x,int y){    int ans=0,res;    while(top[x]!=top[y])    {        if(dep[top[x]]>dep[top[y]])        {            res=getval(1,edge_id[top[x]],edge_id[x]);            x=pre[top[x]];        }        else        {            res=getval(1,edge_id[top[y]],edge_id[y]);            y=pre[top[y]];        }        if(res>ans)ans=res;    }    if(dep[x]<dep[y])    {        if(edge_id[heavy[x]]<edge_id[y])            res=getval(1,edge_id[heavy[x]],edge_id[y]);        else res=getval(1,edge_id[y],edge_id[heavy[x]]);    }    if(dep[x]>dep[y])    {        if(edge_id[heavy[y]]<edge_id[x])            res=getval(1,edge_id[heavy[y]],edge_id[x]);        else res=getval(1,edge_id[x],edge_id[heavy[y]]);    }    if(res>ans)ans=res;    return ans;}int main(){    int T;    scanf("%d",&T);    while(T--)    {        init();        int n;        scanf("%d",&n);        for(int i=1; i<=n-1; i++)        {            int x,y,z;            scanf("%d%d%d",&x,&y,&z);            G[x].push_back(edge(y,i,z));            G[y].push_back(edge(x,i,z));        }        dfs(1,0,1);        slpf(1,0,1);        for(int i=1; i<=n; i++)            if(pre[i])a[edge_id[i]]=val[i];        build(1,1,n-1);        while(1)        {            char op[10];            int x,y;            scanf("%s",op);            if(op[0]=='D')break;            scanf("%d%d",&x,&y);            if(op[0]=='Q')printf("%d\n",getmax(x,y));            if(op[0]=='C')update(1,edge_id[ith[x]],y);        }        printf("\n");        for(int i=1; i<=n; i++)            G[i].clear();    }    return 0;}

题目链接:Aragorn's Story

树链剖分(权值在点上)[区间修改 询问单点值]:

struct node{    int tl,tr,lazy,sum;    node():lazy(0),sum(0) {}}tree[200020];int a[50005];void pushup(int id){    tree[id].sum=tree[id<<1].sum+tree[id<<1|1].sum;}void build(int id,int tl,int tr){    tree[id].tl=tl,tree[id].tr=tr;    tree[id].lazy=tree[id].sum=0;    if(tl==tr)tree[id].sum=a[tl];    else    {        int tm=(tr+tl)>>1;        build(id<<1,tl,tm);        build(id<<1|1,tm+1,tr);        pushup(id);    }}void pushdown(int id){    if(!tree[id].lazy)return;    tree[id<<1].lazy+=tree[id].lazy;    tree[id<<1|1].lazy+=tree[id].lazy;    tree[id<<1].sum+=(tree[id<<1].tr-tree[id<<1].tl+1)*tree[id].lazy;    tree[id<<1|1].sum+=(tree[id<<1|1].tr-tree[id<<1|1].tl+1)*tree[id].lazy;    tree[id].lazy=0;}void update(int id,int ql,int qr,int val){    int tl=tree[id].tl,tr=tree[id].tr;    if(ql>tr || qr<tl)return;    if(ql<=tl && tr<=qr)    {        tree[id].lazy+=val;        tree[id].sum+=(tr-tl+1)*val;        return;    }    pushdown(id);    update(id<<1,ql,qr,val);    update(id<<1|1,ql,qr,val);    pushup(id);}int get_sum(int id,int ql,int qr){    int tl=tree[id].tl,tr=tree[id].tr;    if(ql>tr || qr<tl)return 0;    if(ql<=tl && tr<=qr)return tree[id].sum;    int ans=0;    pushdown(id);    ans+=get_sum(id<<1,ql,qr);    ans+=get_sum(id<<1|1,ql,qr);    pushup(id);    return ans;}int pre[50005],siz[50005],dep[50005];int top[50005],node_id[50005],heavy[50005];int val[50005],idx=0;vector<int>G[50005];int dfs(int x,int fa,int depth){    dep[x]=depth,pre[x]=fa;    int res=1,maxx=0;    int len=G[x].size();    for(int i=0; i<len; i++)    {        if(G[x][i]==fa)continue;        int t=dfs(G[x][i],x,depth+1);        if(t>maxx)maxx=t,heavy[x]=G[x][i];        res+=t;    }    return siz[x]=res;}void slpf(int x,int fa,int tp){    node_id[x]=++idx,top[x]=tp;    int len=G[x].size();    if(heavy[x])slpf(heavy[x],x,tp);    for(int i=0; i<len; i++)    {        int nex=G[x][i];        if(nex==fa)continue;        if(nex!=heavy[x])slpf(nex,x,nex);    }}void change(int x,int y,int z){    while(top[x]!=top[y])    {        if(dep[top[x]]>dep[top[y]])        {            update(1,node_id[top[x]],node_id[x],z);            x=pre[top[x]];        }        else        {            update(1,node_id[top[y]],node_id[y],z);            y=pre[top[y]];        }    }    if(dep[x]>dep[y])swap(x,y);    update(1,node_id[x],node_id[y],z);}void init(void){    idx=0;    memset(a,0,sizeof(a));    memset(val,0,sizeof(val));    memset(top,0,sizeof(top));    memset(pre,0,sizeof(pre));    memset(siz,0,sizeof(siz));    memset(dep,0,sizeof(dep));    memset(heavy,0,sizeof(heavy));    memset(tree,0,sizeof(tree));    memset(node_id,0,sizeof(node_id));}int main(){    int n,m,q;    while(~scanf("%d%d%d",&n,&m,&q))    {        init();        for(int i=1;i<=n;i++)            scanf("%d",&val[i]);        for(int i=1;i<=m;i++)        {            int x,y;            scanf("%d%d",&x,&y);            G[x].push_back(y);            G[y].push_back(x);        }        dfs(1,0,1);        slpf(1,0,1);        for(int i=1;i<=n;i++)            a[node_id[i]]=val[i];        build(1,1,n);        while(q--)        {            char op[2];int x,y,z;            scanf("%s",op);            if(op[0]=='I')            {                scanf("%d%d%d",&x,&y,&z);                change(x,y,z);            }            if(op[0]=='D')            {                scanf("%d%d%d",&x,&y,&z);                change(x,y,-z);            }            if(op[0]=='Q')            {                scanf("%d",&x);                printf("%d\n",get_sum(1,node_id[x],node_id[x]));            }        }        for(int i=1;i<=n;i++)G[i].clear();    }    return 0;}

题目链接:软件包管理器

树链剖分(权值在点上)[区间修改 询问区间和]:

struct node{    int tl,tr,lazy,sum;    node():lazy(-1),sum(0) {}}tree[400020];inline void pushup(int id){    tree[id].sum=tree[id<<1].sum+tree[id<<1|1].sum;}void build(int id,int tl,int tr){    tree[id].tl=tl,tree[id].tr=tr;    if(tl==tr)tree[id].lazy=-1;    else    {        int tm=(tr+tl)>>1;        build(id<<1,tl,tm);        build(id<<1|1,tm+1,tr);        pushup(id);    }}void pushdown(int id){    if(tree[id].lazy==-1)return;    tree[id<<1].lazy=tree[id].lazy;    tree[id<<1|1].lazy=tree[id].lazy;    tree[id<<1].sum=(tree[id<<1].tr-tree[id<<1].tl+1)*tree[id].lazy;    tree[id<<1|1].sum=(tree[id<<1|1].tr-tree[id<<1|1].tl+1)*tree[id].lazy;    tree[id].lazy=-1;}void update(int id,int ql,int qr,int val){    int tl=tree[id].tl,tr=tree[id].tr;    if(ql>tr || qr<tl)return;    if(ql<=tl && tr<=qr)    {        tree[id].lazy=val;        tree[id].sum=(tr-tl+1)*val;        return;    }    pushdown(id);    update(id<<1,ql,qr,val);    update(id<<1|1,ql,qr,val);    pushup(id);}int get_sum(int id,int ql,int qr){    int tl=tree[id].tl,tr=tree[id].tr;    if(ql>tr || qr<tl)return 0;    if(ql<=tl && tr<=qr)return tree[id].sum;    int ans=0;    pushdown(id);    ans+=get_sum(id<<1,ql,qr);    ans+=get_sum(id<<1|1,ql,qr);    pushup(id);    return ans;}int uninall(int id,int ql,int qr){    int tl=tree[id].tl,tr=tree[id].tr;    if(ql>tr || qr<tl)return 0;    if(ql<=tl && tr<=qr)    {        int ans=tree[id].sum;        tree[id].lazy=0;        tree[id].sum=0;        return ans;    }    int ans=0;    pushdown(id);    ans+=uninall(id<<1,ql,qr);    ans+=uninall(id<<1|1,ql,qr);    pushup(id);    return ans;}int pre[100005],siz[100005],dep[100005];int top[100005],node_id[100005],heavy[100005];int lson[100005],rson[100005],idx=0;struct{    int nex,nex_node;} edge[100005];int head[100005],cont=0;void add_edge(int now,int nex){    edge[cont].nex=nex;    edge[cont].nex_node=head[now];    head[now]=cont++;}int dfs(int x,int fa,int depth){    dep[x]=depth,pre[x]=fa;    int res=1,maxx=0;    for(int i=head[x];~i;i=edge[i].nex_node)    {        int nex=edge[i].nex;        if(nex==fa)continue;        int t=dfs(nex,x,depth+1);        if(t>maxx)maxx=t,heavy[x]=nex;        res+=t;    }    return siz[x]=res;}void slpf(int x,int fa,int tp){    lson[x]=node_id[x]=++idx;    top[x]=tp;    if(heavy[x])slpf(heavy[x],x,tp);    for(int i=head[x];~i;i=edge[i].nex_node)    {        int nex=edge[i].nex;        if(nex==fa)continue;        if(nex!=heavy[x])slpf(nex,x,nex);    }    rson[x]=idx;}int getsum(int x,int y,int z){    int ans=0,res;    while(top[x]!=top[y])    {        if(dep[top[x]]>dep[top[y]])        {            res=get_sum(1,node_id[top[x]],node_id[x]);            update(1,node_id[top[x]],node_id[x],z);            x=pre[top[x]];        }        else        {            res=get_sum(1,node_id[top[y]],node_id[y]);            update(1,node_id[top[y]],node_id[y],z);            y=pre[top[y]];        }        ans+=res;    }    if(dep[x]>dep[y])swap(x,y);    res=get_sum(1,node_id[x],node_id[y]);    update(1,node_id[x],node_id[y],z);    ans+=res;    return ans;}int main(){    memset(head,-1,sizeof(head));    int n,t;    scanf("%d",&n);    for(int i=2;i<=n;i++)    {        scanf("%d",&t);        add_edge(t+1,i);    }    dfs(1,0,1);    slpf(1,0,1);    build(1,1,n);    int q;    scanf("%d",&q);    while(q--)    {        char op[15];int x;        scanf("%s%d",op,&x);        if(op[0]=='i')        {            int res=getsum(x+1,1,1);            printf("%d\n",dep[x+1]-res);        }        else        {            int res=uninall(1,lson[x+1],rson[x+1]);            printf("%d\n",res);        }    }    return 0;}


作者:fo0Old
链接:http://www.jianshu.com/p/03f365028725
來源:简书