线段树总结


title: 线段树
date: 2022-05-13 00:05:51
tags:


线段树

动态开点

在这里插入图片描述

#include<bits/stdc++.h>
using namespace std;
const int N=1e7+5e6+10;
int ls[N],rs[N],root,sum[N],idx,lazy[N];
int n,q,ql,qr,k;
void pushup(int u){
    sum[u]=sum[ls[u]]+sum[rs[u]];
}
void pushdown(int u,int l,int r){
    if(lazy[u]==-1)return;
    if(!ls[u])ls[u]=++idx;
    if(!rs[u])rs[u]=++idx;
    lazy[ls[u]]=lazy[rs[u]]=lazy[u];
    int mid=l+r>>1;
    sum[ls[u]]=(mid-l+1)*lazy[u];
    sum[rs[u]]=(r-mid)*lazy[u];
    lazy[u]=-1;
    //动态开点的结点是不能写成递归的形式,要确切给定操作区间
}
void modify(int &u,int l,int r,int ql,int qr,int k){
    if(!u)u=++idx;
    if(r<ql||l>qr)return;
    if(l>=ql&&r<=qr){
        sum[u]=(r-l+1)*k;
        lazy[u]=k;
        return;
    }
    pushdown(u,l,r);
    int mid=l+r>>1;
    if(ql<=mid)modify(ls[u],l,mid,ql,qr,k);
    if(qr>mid)modify(rs[u],mid+1,r,ql,qr,k);
    pushup(u);
}
signed main(){
    ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);
    cin>>n>>q;
    for(int i=0;i<N;i++)lazy[i]=-1;
    modify(root,1,n,1,n,0);
    //根节点为root的点占据的区间是1-n
    //这个操作是把【1,n】这个区间推平为0
    while(q--){
        cin>>ql>>qr>>k;
        modify(root,1,n,ql,qr,2-k);
        cout<<n-sum[root]<<'\n';
    }
    
}

把边权化为点权

在这里插入图片描述
在这里插入图片描述

#include<bits/stdc++.h>
#define int long long
using namespace std;
const int N=1e6+10,M=2*N;
int h[N],e[M],ne[M],w[M],idx,cnt,fa[N],top[N],nw[N],dep[N],tmp[N];
int id[N],sz[N],son[N];
typedef pair<int, int> PII;
PII ab[N];
int n,x,y,a,b,c,m;
string op;
struct node{
    int sum,max,min,lazy;
}t[N*4];
void add(int a,int b,int c){
    e[++idx]=b,w[idx]=c,ne[idx]=h[a],h[a]=idx;
}
void dfs1(int u,int father){
    dep[u]=dep[father]+1,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);
        tmp[j]=w[i];
        sz[u]+=sz[j];
        if(sz[son[u]]<sz[j])son[u]=j;
    }
}
void dfs2(int x,int t){
    id[x]=++cnt,nw[cnt]=tmp[x],top[x]=t;
    if(son[x])dfs2(son[x],t);
    for(int i=h[x];i;i=ne[i]){
        int j=e[i];
        if(j==fa[x]||j==son[x])continue;
        dfs2(j,j);
    }
}
void pushup(int u){
    t[u].sum=t[u<<1].sum+t[u<<1|1].sum;
    t[u].max=max(t[u<<1].max,t[u<<1|1].max);
    t[u].min=min(t[u<<1].min,t[u<<1|1].min);
}
void pushdown(int u){
    if(t[u].lazy==0)return;
    auto &L=t[u<<1];
    auto &R=t[u<<1|1];
    L.lazy^=1,R.lazy^=1;
    L.sum=-L.sum,L.max=-L.max,L.min=-L.min;
    R.sum=-R.sum,R.max=-R.max,R.min=-R.min;
    swap(L.max,L.min),swap(R.max,R.min);
    t[u].lazy=0;
}
void build(int u=1,int l=1,int r=n){
    t[u]={nw[l],nw[l],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 modify(int u,int l,int r,int i,int k){
    if(l==r){
        t[u].sum=t[u].max=t[u].min=k;
        return;
    }
    pushdown(u);
    int mid=l+r>>1;
    if(i<=mid)modify(u<<1,l,mid,i,k);
    else modify(u<<1|1,mid+1,r,i,k);
    pushup(u);
}
void update(int u,int l,int r,int ql,int qr,int lazy=1){
    if(l>qr||r<ql)return;
    if(l>=ql&&r<=qr){
        t[u].sum=-t[u].sum;
        t[u].max=-t[u].max;
        t[u].min=-t[u].min;
        swap(t[u].max,t[u].min);
        t[u].lazy^=1;
        return;
    }
    pushdown(u);
    int mid=l+r>>1;
    if(ql<=mid)update(u<<1,l,mid,ql,qr);
    if(qr>mid)update(u<<1|1,mid+1,r,ql,qr);
    pushup(u);
}
int qmax(int u,int l,int r,int ql,int qr){
    if(l>qr||r<ql)return -1e9;
    if(l>=ql&&r<=qr)return t[u].max;
    pushdown(u);
    int mid=l+r>>1;
    int ans=-1e9;
    if(ql<=mid)ans=max(ans,qmax(u<<1,l,mid,ql,qr));
    if(qr> mid)ans=max(ans,qmax(u<<1|1,mid+1,r,ql,qr));
    return ans;
}
int qmin(int u,int l,int r,int ql,int qr){
    if(l>qr||r<ql)return 1e9;
    if(l>=ql&&r<=qr)return t[u].min;
    pushdown(u);
    int mid=l+r>>1;
    int ans=1e9;
    if(ql<=mid)ans=min(ans,qmin(u<<1,l,mid,ql,qr));
    if(qr> mid)ans=min(ans,qmin(u<<1|1,mid+1,r,ql,qr));
    return ans;
}
int qsum(int u,int l,int r,int ql,int qr){
    if(l>qr||r<ql)return 0;
    if(l>=ql&&r<=qr)return t[u].sum;
    pushdown(u);
    int mid=l+r>>1;
    int ans=0;
    if(ql<=mid)ans+=qsum(u<<1,l,mid,ql,qr);
    if(qr> mid)ans+=qsum(u<<1|1,mid+1,r,ql,qr);
    return ans;
}
/* 上面是线段树,下面是树链剖分*/
void update(int x,int y){
    while(top[x]!=top[y]){
        if(dep[top[x]]<dep[top[y]])swap(x,y);
        update(1,1,n,id[top[x]],id[x]);
        x=fa[top[x]];
    }
    if(dep[x]>dep[y])swap(x,y);
    if(x!=y)update(1,1,n,id[x]+1,id[y]);
}
int qmax(int x,int y){
    int ans=-1e9;
    while(top[x]!=top[y]){
        if(dep[top[x]]<dep[top[y]])swap(x,y);
        ans=max(ans, qmax(1,1,n,id[top[x]],id[x]) );
        x=fa[top[x]];
    }
    if(dep[x]>dep[y])swap(x,y);
    if(x!=y)ans=max(ans,qmax(1,1,n,id[x]+1,id[y]));
    return ans;
}

int qmin(int x,int y){
    int ans=1e9;
    while(top[x]!=top[y]){
        if(dep[top[x]]<dep[top[y]])swap(x,y);
        ans=min(ans, qmin(1,1,n,id[top[x]],id[x]));
        x=fa[top[x]];
    }
    if(dep[x]>dep[y])swap(x,y);
    if(x!=y)ans=min(ans,qmin(1,1,n,id[x]+1,id[y]));
    return ans;
}
int qsum(int x,int y){
    int ans=0;
    while(top[x]!=top[y]){
        if(dep[top[x]]<dep[top[y]])swap(x,y);
        ans+=qsum(1,1,n,id[top[x]],id[x]);
        x=fa[top[x]];
    }
    if(dep[x]>dep[y])swap(x,y);
    if(x!=y)ans+=qsum(1,1,n,id[x]+1,id[y]);
    return ans;
}

signed main(){
    ios::sync_with_stdio(0);
    cin.tie(0);
    cout.tie(0);
    cin>>n;
    for(int i=1;i<n;i++){
        cin>>a>>b>>c;
        a++,b++;
        ab[i]={a,b};
        add(a,b,c);
        add(b,a,c);
    }
    dfs1(1,0);
    dfs2(1,1);
    build(1,1,n);
    cin>>m;
    while(m--){
        cin>>op>>x>>y;
        if(op=="C"){
            int a=ab[x].first;
            int b=ab[x].second;
            if(dep[a]<dep[b])swap(a,b);
            modify(1,1,n,id[a],y);
            continue;
        }
        x++,y++;
        if(op=="N")update(x,y);
        if(op=="SUM")cout<<qsum(x,y)<<'\n';
        if(op=="MAX")cout<<qmax(x,y)<<'\n';
        if(op=="MIN")cout<<qmin(x,y)<<'\n';
    }
}

拓展

如果是在有颜色的树上修改呢

颜色个数为1e5

也就是说这道题要动态开点来写

#include<bits/stdc++.h>
#define int long long
#define remove _
using namespace std;
const int N=1e6+10,M=2*N;
int h[N],e[M],ne[M],w[M],idx,cnt,fa[N],top[N],nw[N],dep[N],tmp[N];
int id[N],sz[N],son[N];
typedef pair<int, int> PII;
PII ab[N];
int n,x,y,a,b,c,m;
string op;
int rt;
// struct node{
//     int sum,max,min,lazy;
// }t[N*4];
struct node{
    int sum,max,min,lazy;
    int ls,rs;
}t[N*4];
int root[N];
int color[N];
void add(int a,int b,int c){
    e[++idx]=b,w[idx]=c,ne[idx]=h[a],h[a]=idx;
}
void dfs1(int u,int father){
    dep[u]=dep[father]+1,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);
        tmp[j]=w[i];
        sz[u]+=sz[j];
        if(sz[son[u]]<sz[j])son[u]=j;
    }
}
void dfs2(int x,int t){
    id[x]=++cnt,nw[cnt]=tmp[x],top[x]=t;
    if(son[x])dfs2(son[x],t);
    for(int i=h[x];i;i=ne[i]){
        int j=e[i];
        if(j==fa[x]||j==son[x])continue;
        dfs2(j,j);
    }
}
void pushup(int u){
    t[u].sum=t[t[u].ls].sum+t[t[u].rs].sum;
    t[u].max=max(t[t[u].ls].max,t[t[u].rs].max);
    t[u].min=min(t[t[u].ls].min,t[t[u].rs].min);
}
void pushdown(int u){
    if(t[u].lazy==0)return;
    if(!t[u].ls)t[u].ls=++rt;
    if(!t[u].rs)t[u].rs=++rt;
    auto &L=t[t[u].ls];
    auto &R=t[t[u].rs];
    L.lazy^=1,R.lazy^=1;
    L.sum=-L.sum,L.max=-L.max,L.min=-L.min;
    R.sum=-R.sum,R.max=-R.max,R.min=-R.min;
    swap(L.max,L.min),swap(R.max,R.min);
    t[u].lazy=0;
}
// void build(int u=1,int l=1,int r=n){
//     t[u]={nw[l],nw[l],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 modify(int &u,int l,int r,int i,int k){
    if(!u)u=++rt;
    if(l==r){
        t[u].sum=t[u].max=t[u].min=k;
        return;
    }
    pushdown(u);
    int mid=l+r>>1;
    if(i<=mid)modify(t[u].ls,l,mid,i,k);
    else modify(t[u].rs,mid+1,r,i,k);
    pushup(u);
}
void remove(int &u,int l,int r,int i,int k){
    if(l==r){
        t[u].max=-1e9;
        t[u].sum=0;
        t[u].min=1e9;
        t[u].lazy=0;
        return;
    }
    int mid=l+r>>1;
    pushdown(u);
    if(i<=mid)remove(t[u].ls,l,mid,i,k);
    else remove(t[u].rs,mid+1,r,i,k);
    pushup(u);
}
void update(int &u,int l,int r,int ql,int qr,int lazy=1){
    if(l>qr||r<ql)return;
    if(!u)u=++rt;
    if(l>=ql&&r<=qr){
        t[u].sum=-t[u].sum;
        t[u].max=-t[u].max;
        t[u].min=-t[u].min;
        swap(t[u].max,t[u].min);
        t[u].lazy^=1;
        return;
    }
    pushdown(u);
    int mid=l+r>>1;
    if(ql<=mid)update(t[u].ls,l,mid,ql,qr);
    if(qr>mid)update(t[u].rs,mid+1,r,ql,qr);
    pushup(u);
}
int qmax(int u,int l,int r,int ql,int qr){
    if(!u)return -1e9;
    if(l>qr||r<ql)return -1e9;
    if(l>=ql&&r<=qr)return t[u].max;
    pushdown(u);
    int mid=l+r>>1;
    int ans=-1e9;
    if(ql<=mid)ans=max(ans,qmax(t[u].ls,l,mid,ql,qr));
    if(qr> mid)ans=max(ans,qmax(t[u].rs,mid+1,r,ql,qr));
    return ans;
}
int qmin(int u,int l,int r,int ql,int qr){
    if(!u)return 1e9;
    if(l>qr||r<ql)return 1e9;
    if(l>=ql&&r<=qr)return t[u].min;
    pushdown(u);
    int mid=l+r>>1;
    int ans=1e9;
    if(ql<=mid)ans=min(ans,qmin(t[u].ls,l,mid,ql,qr));
    if(qr> mid)ans=min(ans,qmin(t[u].rs,mid+1,r,ql,qr));
    return ans;
}
int qsum(int u,int l,int r,int ql,int qr){
    if(!u)return 0;
    if(l>qr||r<ql)return 0;
    if(l>=ql&&r<=qr)return t[u].sum;
    pushdown(u);
    int mid=l+r>>1;
    int ans=0;
    if(ql<=mid)ans+=qsum(t[u].ls,l,mid,ql,qr);
    if(qr> mid)ans+=qsum(t[u].rs,mid+1,r,ql,qr);
    return ans;
}
/* 上面是线段树,下面是树链剖分*/
void update(int &o,int x,int y){
    while(top[x]!=top[y]){
        if(dep[top[x]]<dep[top[y]])swap(x,y);
        update(o,1,n,id[top[x]],id[x]);
        x=fa[top[x]];
    }
    if(dep[x]>dep[y])swap(x,y);
    if(x!=y)update(o,1,n,id[x]+1,id[y]);
}
int qmax(int o,int x,int y){
    int ans=-1e9;
    while(top[x]!=top[y]){
        if(dep[top[x]]<dep[top[y]])swap(x,y);
        ans=max(ans, qmax(o,1,n,id[top[x]],id[x]) );
        x=fa[top[x]];
    }
    if(dep[x]>dep[y])swap(x,y);
    if(x!=y)ans=max(ans,qmax(o,1,n,id[x]+1,id[y]));
    return ans;
}

int qmin(int o,int x,int y){
    int ans=1e9;
    while(top[x]!=top[y]){
        if(dep[top[x]]<dep[top[y]])swap(x,y);
        ans=min(ans, qmin(o,1,n,id[top[x]],id[x]));
        x=fa[top[x]];
    }
    if(dep[x]>dep[y])swap(x,y);
    if(x!=y)ans=min(ans,qmin(o,1,n,id[x]+1,id[y]));
    return ans;
}
int qsum(int o,int x,int y){
    int ans=0;
    while(top[x]!=top[y]){
        if(dep[top[x]]<dep[top[y]])swap(x,y);
        ans+=qsum(o,1,n,id[top[x]],id[x]);
        x=fa[top[x]];
    }
    if(dep[x]>dep[y])swap(x,y);
    if(x!=y)ans+=qsum(o,1,n,id[x]+1,id[y]);
    return ans;
}

signed main(){
    ios::sync_with_stdio(0);
    cin.tie(0);
    cout.tie(0);
    cin>>n;
    for(int i=1;i<n;i++){
        cin>>a>>b>>c;
        a++,b++;
        ab[i]={a,b};
        add(a,b,c);
        add(b,a,c);
    }
    dfs1(1,0);
    dfs2(1,1);
    //build(1,1,n);
    for(int i=1;i<=n;i++)color[i]=1;
    for(int i=1;i<=n;i++)modify(root[color[i]],1,n,id[i],tmp[i]);
    cin>>m;
    while(m--){
        cin>>op>>x>>y;
        if(op=="C"){
            int a=ab[x].first;
            int b=ab[x].second;
            if(dep[a]<dep[b])swap(a,b);
            remove(root[color[a]],1,n,id[a],0);
            modify(root[color[a]],1,n,id[a],y);
            continue;
        }
        x++,y++;
        if(op=="N")update(root[color[x]],x,y);
        if(op=="SUM")cout<<qsum(root[color[x]],x,y)<<'\n';
        if(op=="MAX")cout<<qmax(root[color[x]],x,y)<<'\n';
        if(op=="MIN")cout<<qmin(root[color[x]],x,y)<<'\n';
    }
}

线段树合并

在这里插入图片描述

对每一个节点开一个权值线段树

用动态开点,不然会mle

而且不要直接#define int long long 只在关键变量开long long不然还是会MLE

#include<bits/stdc++.h>
// #define int long long
using namespace std;
const int N=1e5+10,M=2*N;
int h[N],e[M],ne[M],idx;
int n,m,c[N],root[N],cnt;
long long ans[N];
struct node{
    int l,r;
    long long sum;//主要颜色的编号和
    int max;//出现最多颜色的次数
    #define ls tr[u].l
    #define rs tr[u].r
}tr[N*100];
void add(int a,int b){
    e[++idx]=b,ne[idx]=h[a],h[a]=idx;
}
void pushup(int u){
    tr[u].max=max(tr[ls].max,tr[rs].max);
    if(tr[ls].max==tr[rs].max)tr[u].sum=tr[ls].sum+tr[rs].sum;
    if(tr[ls].max >tr[rs].max)tr[u].sum=tr[ls].sum;
    if(tr[ls].max <tr[rs].max)tr[u].sum=tr[rs].sum;
}
void pushdown(int u){
    
}
void modify(int &o,int l,int r,int i,int k){
    if(!o)o=++cnt;
    if(l==r){
        tr[o].max=1;
        tr[o].sum=k;
        return;
    }
    int mid=l+r>>1;
    if(i<=mid)modify(tr[o].l,l,mid,i,k);
    else modify(tr[o].r,mid+1,r,i,k);
    pushup(o);
}
int merge(int a,int b,int l,int r){//线段树合并
    if(!a)return b;
    if(!b)return a;//哪个没有就返回另一个点的编号
    if(l==r){
        tr[a].max+=tr[b].max;
        return a;
    }
    int mid=l+r>>1;
    tr[a].l=merge(tr[a].l,tr[b].l,l,mid);//合并a,b的左儿子
    tr[a].r=merge(tr[a].r,tr[b].r,mid+1,r);//合并a,b的右儿子
    pushup(a);
    return a;
}
void cal(int u,int fa=0){
    for(int i=h[u];i;i=ne[i]){
        int j=e[i];
        if(j==fa)continue;
        cal(j,u);
        root[u]=merge(root[u],root[j],1,n);
    }
    ans[u]=tr[root[u]].sum;
}
signed main(){
    ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);
    cin>>n;
    for(int i=1;i<=n;i++)cin>>c[i];
    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++)modify(root[i],1,n,c[i],c[i]);
    cal(1);
    for(int i=1;i<=n;i++)cout<<ans[i]<<" ";
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值