树链剖分总结

树链剖分

模板

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-lASA0NYW-1652371643540)(C:/Users/Lenovo/AppData/Roaming/Typora/typora-user-images/image-20220511062007989.png)]

#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;
#define int long long
const int N = 100010 , M=N*2;
int n,m;
int w[N],h[N],ne[M],e[M],idx;
int id[N],nw[N],cnt;
int dep[N],sz[N],top[N],fa[N],son[N];

struct Tree{
    int l,r;
    int add,sum;
}tr[N*4];

void add(int a, int b)  
{
    e[idx] = b, ne[idx] = h[a], h[a] = idx ++ ;
}

void dfs1(int u,int father,int depth){
    dep[u]=depth,fa[u]=father,sz[u]=1;
    for(int i=h[u];~i;i=ne[i]){
        int j=e[i];
        if(j==father)continue;
        dfs1(j,u,depth+1);
        sz[u]+=sz[j];
        if(sz[son[u]<sz[j]])son[u]=j;
    }
}

void dfs2(int u,int t){
    id[u]=++cnt,nw[cnt]=w[u],top[u]=t;
    if(!son[u])return;
    dfs2(son[u],t);
    for(int i=h[u];~i;i=ne[i]){
        int j=e[i];
        if(j==fa[u]||j==son[u])continue;
        dfs2(j,j);
    }
}

void pushup(int u){
    tr[u].sum=tr[u<<1].sum+tr[u<<1|1].sum;
}

void pushdown(int u){
    auto &root=tr[u], &left=tr[u<<1], &right=tr[u<<1|1];
    if(root.add){
        left.add+=root.add;
        left.sum+=root.add*(left.r-left.l+1);
        right.add+=root.add;
        right.sum+=root.add*(right.r-right.l+1);
        root.add=0;
    }
}

void build(int u,int l,int r){
    tr[u]={l,r,0,nw[l]};
    if(l==r)return;
    int mid=l+r>>1;
    build(u<<1,l,mid),build(u<<1|1,mid+1,r);
    pushup(u);
}

void update(int u,int l,int r,int k){
    if(l<=tr[u].l&&r>=tr[u].r){
        tr[u].add+=k;
        tr[u].sum+=k*(tr[u].r-tr[u].l+1);
        return;
    }
    pushdown(u);
    int mid=tr[u].l+tr[u].r>>1;
    if(l<=mid)update(u<<1,l,r,k);
    if(r>mid)update(u<<1|1,l,r,k);
    pushup(u);
}

int query(int u,int l,int r){
    if(l<=tr[u].l&&tr[u].r<=r)return tr[u].sum;
    pushdown(u);
    int mid=tr[u].l+tr[u].r>>1;
    int ans=0;
    if(l<=mid)ans+=query(u<<1,l,r);
    if(r>mid)ans+=query(u<<1|1,l,r);
    return ans;
}

void update_path(int u, int v, int k)
{
    while (top[u] != top[v])
    {
        if (dep[top[u]] < dep[top[v]]) swap(u, v);
        update(1, id[top[u]], id[u], k);
        u = fa[top[u]];
    }
    if (dep[u] < dep[v]) swap(u, v);
    update(1, id[v], id[u], k);
}

int query_path(int u, int v)
{
    int res = 0;
    while (top[u] != top[v])
    {
        if (dep[top[u]] < dep[top[v]]) swap(u, v);
        res += query(1, id[top[u]], id[u]);
        u = fa[top[u]];
    }
    if (dep[u] < dep[v]) swap(u, v);
    res += query(1, id[v], id[u]);
    return res;
}

void update_tree(int u, int k)
{
    update(1, id[u], id[u] + sz[u] - 1, k);
}

int query_tree(int u)
{
    return query(1, id[u], id[u] + sz[u] - 1);
}



signed main(){
    ios::sync_with_stdio(0);
    cin.tie(0);
    cout.tie(0);
    memset(h,-1,sizeof h);
    cin>>n;
    for(int i=1;i<=n;i++)cin>>w[i];
    for(int i=1;i<n;i++){
        int a,b;
        cin>>a>>b;
        add(a,b),add(b,a);
    }
    dfs1(1,-1,1);
    dfs2(1,1);
    build(1,1,n);
    cin>>m;
    while(m--){
        int t,u,v,k;
        cin>>t>>u;
        if(t==1){
            cin>>v>>k;
            update_path(u,v,k);
        }
        else if(t==2){
            cin>>k;
            update_tree(u,k);
        }
        else if(t==3){
            cin>>v;
            cout<<query_path(u,v)<<endl;
        }
        else cout<<query_tree(u)<<endl;
    }
}

换根

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-5C1S9PCr-1652371643542)(C:/Users/Lenovo/AppData/Roaming/Typora/typora-user-images/image-20220511062522657.png)]

#include <iostream>
#include <cstring>

using namespace std;

typedef long long LL;

const int N = 1e5 + 10, M = N << 1;

int n, m;
int h[N], e[M], ne[M], w[M], idx;
int id[N], nw[N], cnt;
int dep[N], sz[N], top[N], fa[N], son[N];
int root;
struct SegmentTree
{
    int l, r;
    LL sum, flag;
}tr[N << 2];

void add(int a, int b)
{
    e[idx] = b, ne[idx] = h[a], h[a] = idx ++ ;
}
void dfs1(int u, int father, int depth)
{
    dep[u] = depth, fa[u] = father, sz[u] = 1;
    for (int i = h[u]; ~i; i = ne[i])
    {
        int j = e[i];
        if (j == father) continue;
        dfs1(j, u, depth + 1);
        sz[u] += sz[j];
        if (sz[son[u]] < sz[j]) son[u] = j;
    }
}
void dfs2(int u, int t)
{
    id[u] = ++ cnt, nw[cnt] = w[u], top[u] = t;
    if (!son[u]) return;
    dfs2(son[u], t);
    for (int i = h[u]; ~i; i = ne[i])
    {
        int j = e[i];
        if (j == fa[u] || j == son[u]) continue;
        dfs2(j, j);
    }
}
//------------------------线段树的部分------------------------\\

void pushup(int u)
{
    tr[u].sum = tr[u << 1].sum + tr[u << 1 | 1].sum;
}

void pushdown(int u)
{
    auto &root = tr[u], &left = tr[u << 1], &right = tr[u << 1 | 1];
    if (root.flag)
    {
        left.sum += root.flag * (left.r - left.l + 1);
        left.flag += root.flag;
        right.sum += root.flag * (right.r - right.l + 1);
        right.flag += root.flag;
        root.flag = 0;
    }
}

void build(int u, int l, int r)
{
    tr[u] = {l, r, nw[r], 0};
    if (l == r) return;
    int mid = l + r >> 1;
    build(u << 1, l, mid), build(u << 1 | 1, mid + 1, r);
    pushup(u);
}

void update(int u, int l, int r, int k)
{
    if (l <= tr[u].l && r >= tr[u].r)
    {
        tr[u].flag += k;
        tr[u].sum += k * (tr[u].r - tr[u].l + 1);
        return;
    }
    pushdown(u);
    int mid = tr[u].l + tr[u].r >> 1;
    if (l <= mid) update(u << 1, l, r, k);
    if (r > mid) update(u << 1 | 1, l, r, k);
    pushup(u);
}

LL query(int u, int l, int r)
{
    if (l <= tr[u].l && r >= tr[u].r) return tr[u].sum;
    pushdown(u);
    int mid = tr[u].l + tr[u].r >> 1;
    LL res = 0;
    if (l <= mid) res += query(u << 1, l, r);
    if (r > mid) res += query(u << 1 | 1, l, r);
    return res;
}
//------------------------线段树的部分------------------------\\

int lca(int u, int v)
{
    while (top[u] != top[v])
    {
        if (dep[top[u]] < dep[top[v]]) swap(u, v);
        u = fa[top[u]];
    }
    if (dep[u] > dep[v]) swap(u, v);
    return u;
}
void update_path(int u, int v, int k)
{
    while (top[u] != top[v])
    {
        if (dep[top[u]] < dep[top[v]]) swap(u, v);
        update(1, id[top[u]], id[u], k);
        u = fa[top[u]];
    }
    if (dep[u] < dep[v]) swap(u, v);
    update(1, id[v], id[u], k);
}
LL query_path(int u, int v)
{
    LL res = 0;
    while (top[u] != top[v])
    {
        if (dep[top[u]] < dep[top[v]]) swap(u, v);
        res += query(1, id[top[u]], id[u]);
        u = fa[top[u]];
    }
    if (dep[u] < dep[v]) swap(u, v);
    res += query(1, id[v], id[u]);
    return res;
}
void update_tree(int u, int k)
{
    if (u == root) update(1, 1, n, k);
    else if (lca(u, root) == u)
    {
        update(1, 1, n, k);
        for (int i = h[u]; ~i; i = ne[i])
        {
            int j = e[i];
            if (lca(j, root) == j)
            {
                update(1, id[j], id[j] + sz[j] - 1, -k);
                break;
            }
        }
    }
    else update(1, id[u], id[u] + sz[u] - 1, k);
}
LL query_tree(int u)
{
    if (u == root) return query(1, 1, n);
    else if (lca(u, root) == u)
    {
        LL res = query(1, 1, n);
        for (int i = h[u]; ~i; i = ne[i])
        {
            int j = e[i];
            if (lca(j, root) == j)
            {
                res -= query(1, id[j], id[j] + sz[j] - 1);
                return res;
            }
        }
    }
    else return query(1, id[u], id[u] + sz[u] - 1);
}

int main()
{
    scanf("%d", &n);
    memset(h, -1, sizeof h);
    for (int i = 1; i <= n; i ++ ) scanf("%d", &w[i]);
    for (int i = 2; i <= n; i ++ )
    {
        int a;
        scanf("%d", &a);
        add(a, i);
    }
    dfs1(1, -1, 1);
    dfs2(1, 1);
    build(1, 1, n);
    scanf("%d", &m);
    while (m -- )
    {
        int t, u, v, k;
        scanf("%d%d", &t, &u);
        if (t == 1) root = u;
        else if (t == 2)
        {
            scanf("%d%d", &v, &k);
            update_path(u, v, k);
        }
        else if (t == 3)
        {
            scanf("%d", &k);
            update_tree(u, k);
        }
        else if (t == 4)
        {
            scanf("%d", &v);
            printf("%lld\n", query_path(u, v));
        }
        else printf("%lld\n", query_tree(u));
    }
    return 0;
}

线段树动态开点

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-efqVP2vx-1652371643543)(C:/Users/Lenovo/AppData/Roaming/Typora/typora-user-images/image-20220511210146952.png)]

这道题不能开1e5个线段树,只能动态开点

#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;
#define swpa swap
#define remove _
const int N = 2e6+10, M=N*2;
int n,m,cnt2;
int w[N],h[N],ne[M],e[M],idx;
int id[N],nw[N],cnt;
int dep[N],sz[N],top[N],fa[N],son[N];
int root[N];
struct Tree{
    int ls,rs;
    int sum,mx;
}tr[N*4];
int c[N];
inline void add(int a, int b)  
{
    e[idx] = b, ne[idx] = h[a], h[a] = idx ++ ;
}

void dfs1(int u,int father,int depth){
    dep[u]=depth,fa[u]=father,sz[u]=1;
    for(int i=h[u];~i;i=ne[i]){
        int j=e[i];
        if(j==father)continue;
        dfs1(j,u,depth+1);
        sz[u]+=sz[j];
        if(sz[son[u]]<sz[j])son[u]=j;
    }
}

void dfs2(int u,int t){
    id[u]=++cnt,nw[cnt]=w[u],top[u]=t;
    //who[cnt]=u;
    if(!son[u])return;
    dfs2(son[u],t);
    for(int i=h[u];~i;i=ne[i]){
        int j=e[i];
        if(j==fa[u]||j==son[u])continue;
        dfs2(j,j);
    }
}

inline void pushup(int u){
    tr[u].sum=tr[tr[u].ls].sum+tr[tr[u].rs].sum;
    tr[u].mx=max(tr[tr[u].ls].mx,tr[tr[u].rs].mx);
}
inline void pushdown(int u){
    
}
inline void modify(int &o,int l,int r,int i,int k){
    if(!o)o=++cnt2;
    tr[o].mx=tr[o].sum=k;
    if(l==r)return;
    //pushdown(o);
    int mid=l+r>>1;
    if(i<=mid)modify(tr[o].ls,l,mid,i,k);
    else modify(tr[o].rs,mid+1,r,i,k);
    pushup(o);
    //if(tr[o].sum==0)o=0;
}
void remove(int &o,int l,int r,int i,int k=0){
    if(l==r){tr[o].sum=tr[o].mx=0;return;}
    int mid=l+r>>1;
    if(i<=mid)remove(tr[o].ls,l,mid,i,k);
    else remove(tr[o].rs,mid+1,r,i,k);
    pushup(o);
}
inline int query_max(int u,int ql,int qr,int l,int r){
    if(!u)return -1;
    if(qr<l||ql>r)return -1;
    if(l>=ql&&r<=qr)return tr[u].mx;
    //pushdown(u);
    int mid=l+r>>1;
    return max(query_max(tr[u].ls,ql,qr,l,mid),
               query_max(tr[u].rs,ql,qr,mid+1,r));
}
inline int query_sum(int u,int ql,int qr,int l,int r){
    if(!u)return 0;
    if(qr<l||ql>r)return 0;
    if(l>=ql&&r<=qr)return tr[u].sum;
    //pushdown(u);
    int mid=l+r>>1;
    return query_sum(tr[u].ls,ql,qr,l,mid)+query_sum(tr[u].rs,ql,qr,mid+1,r);
}

inline int query_path_sum(int o,int u, int v)
{
    int res = 0;
    while (top[u] != top[v])
    {
        if (dep[top[u]]<dep[top[v]])swap(u, v);
        res+=query_sum(root[o],id[top[u]],id[u],1,n);
        u=fa[top[u]];
    }
    if (dep[u]>dep[v])swap(u, v);
    res+=query_sum(root[o],id[u],id[v],1,n);
    return res;
}
inline int query_path_max(int o,int u,int v){
    int res=0;
    while(top[u]!=top[v]){
        if(dep[top[u]]<dep[top[v]])swpa(u,v);
        res=max(res,query_max(root[o],id[top[u]],id[u],1,n));
        u=fa[top[u]];
    }
    if(dep[u]>dep[v])swap(u,v);
    res=max(res,query_max(root[o],id[u],id[v],1,n));
    return res;
}
signed main(){
    ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);
    memset(h,-1,sizeof h);
    cin>>n>>m;
    for(int i=1;i<=n;i++)cin>>w[i]>>c[i];
    for(int i=1;i<n;i++){
        int a,b;
        cin>>a>>b;
        add(a,b),add(b,a);
    }
    dfs1(1,-1,1);
    dfs2(1,1);
    for(int i=1;i<=n;i++)modify(root[c[i]],1,n,id[i],w[i]);
    while(m--){
        string op;
        int x,y;
        cin>>op>>x>>y;
        if(op[1]=='C')remove(root[c[x]],1,n,id[x]),modify(root[y],1,n,id[x],w[x]),c[x]=y;
        if(op[1]=='W')remove(root[c[x]],1,n,id[x]),modify(root[c[x]],1,n,id[x],y),w[x]=y;
        if(op[1]=='S')cout<<query_path_sum(c[x],x,y)<<'\n';
        if(op[1]=='M')cout<<query_path_max(c[x],x,y)<<'\n';
    }
}

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-5MFWjXhH-1652371643544)(C:/Users/Lenovo/AppData/Roaming/Typora/typora-user-images/image-20220511211329602.png)]

这种题可以套板子来写

如果有颜色的限制就开个color数组读入颜色,如果没有颜色的限制就把color数组全部置为1

注意如果点权有负数的情况更新最大值的时候是要把-1和0变为-1e9

#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;
#define swpa swap
#define remove _
#define int long long
const int N = 2e6+10, M=N*2;
int n,m,cnt2;
int w[N],h[N],ne[M],e[M],idx;
int id[N],nw[N],cnt;
int dep[N],sz[N],top[N],fa[N],son[N];
int root[N];
struct Tree{
    int ls,rs;
    int sum,mx;
}tr[N*4];
int c[N];
inline void add(int a, int b)  
{
    e[idx] = b, ne[idx] = h[a], h[a] = idx ++ ;
}

void dfs1(int u,int father,int depth){
    dep[u]=depth,fa[u]=father,sz[u]=1;
    for(int i=h[u];~i;i=ne[i]){
        int j=e[i];
        if(j==father)continue;
        dfs1(j,u,depth+1);
        sz[u]+=sz[j];
        if(sz[son[u]]<sz[j])son[u]=j;
    }
}

void dfs2(int u,int t){
    id[u]=++cnt,nw[cnt]=w[u],top[u]=t;
    //who[cnt]=u;
    if(!son[u])return;
    dfs2(son[u],t);
    for(int i=h[u];~i;i=ne[i]){
        int j=e[i];
        if(j==fa[u]||j==son[u])continue;
        dfs2(j,j);
    }
}

inline void pushup(int u){
    tr[u].sum=tr[tr[u].ls].sum+tr[tr[u].rs].sum;
    tr[u].mx=max(tr[tr[u].ls].mx,tr[tr[u].rs].mx);
}
inline void pushdown(int u){
    
}
inline void modify(int &o,int l,int r,int i,int k){
    if(!o)o=++cnt2;
    tr[o].mx=tr[o].sum=k;
    if(l==r)return;
    //pushdown(o);
    int mid=l+r>>1;
    if(i<=mid)modify(tr[o].ls,l,mid,i,k);
    else modify(tr[o].rs,mid+1,r,i,k);
    pushup(o);
    //if(tr[o].sum==0)o=0;
}
void remove(int &o,int l,int r,int i,int k=0){
    if(l==r){tr[o].sum=tr[o].mx=0;return;}
    int mid=l+r>>1;
    if(i<=mid)remove(tr[o].ls,l,mid,i,k);
    else remove(tr[o].rs,mid+1,r,i,k);
    pushup(o);
}
inline int query_max(int u,int ql,int qr,int l,int r){
    if(!u)return -1e9;
    if(qr<l||ql>r)return -1e9;
    if(l>=ql&&r<=qr)return tr[u].mx;
    //pushdown(u);
    int mid=l+r>>1;
    return max(query_max(tr[u].ls,ql,qr,l,mid),
               query_max(tr[u].rs,ql,qr,mid+1,r));
}
inline int query_sum(int u,int ql,int qr,int l,int r){
    if(!u)return 0;
    if(qr<l||ql>r)return 0;
    if(l>=ql&&r<=qr)return tr[u].sum;
    //pushdown(u);
    int mid=l+r>>1;
    return query_sum(tr[u].ls,ql,qr,l,mid)+query_sum(tr[u].rs,ql,qr,mid+1,r);
}

inline int query_path_sum(int o,int u, int v)
{
    int res = 0;
    while (top[u] != top[v])
    {
        if (dep[top[u]]<dep[top[v]])swap(u, v);
        res+=query_sum(root[o],id[top[u]],id[u],1,n);
        u=fa[top[u]];
    }
    if (dep[u]>dep[v])swap(u, v);
    res+=query_sum(root[o],id[u],id[v],1,n);
    return res;
}
inline int query_path_max(int o,int u,int v){
    int res=-1e9;
    while(top[u]!=top[v]){
        if(dep[top[u]]<dep[top[v]])swpa(u,v);
        res=max(res,query_max(root[o],id[top[u]],id[u],1,n));
        u=fa[top[u]];
    }
    if(dep[u]>dep[v])swap(u,v);
    res=max(res,query_max(root[o],id[u],id[v],1,n));
    return res;
}
signed main(){
    ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);
    memset(h,-1,sizeof h);
    cin>>n;
    
    for(int i=1;i<n;i++){
        int a,b;
        cin>>a>>b;
        add(a,b),add(b,a);
    }
    for(int i=1;i<=n;i++)cin>>w[i];
    for(int i=1;i<=n;i++)c[i]=1;
    dfs1(1,-1,1);
    dfs2(1,1);
    for(int i=1;i<=n;i++)modify(root[c[i]],1,n,id[i],w[i]);
    cin>>m;
    while(m--){
        string op;
        int x,y;
        cin>>op>>x>>y;
        //if(op=="CHANGE")remove(root[c[x]],1,n,id[x]),modify(root[y],1,n,id[x],w[x]),c[x]=y;
        if(op=="CHANGE")remove(root[c[x]],1,n,id[x]),modify(root[c[x]],1,n,id[x],y),w[x]=y;
        if(op=="QSUM")cout<<query_path_sum(c[x],x,y)<<'\n';
        if(op=="QMAX")cout<<query_path_max(c[x],x,y)<<'\n';
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值