zoukankan      html  css  js  c++  java
  • 【知识点】线段树相关算法

    线段树合并:

    一般是将若干棵权值线段树的信息整合到一棵权值线段树上。均摊复杂度$O(nlog{n})$。

    同时遍历两棵线段树,若某一边没有节点则直接返回另一边的节点,否则继续遍历直到$l=r$。

    #include<bits/stdc++.h>
    #define maxn 1000005
    #define maxm 500005
    #define inf 0x7fffffff
    #define ll long long
    #define rint register int
    #define debug(x) cerr<<#x<<": "<<x<<endl
    #define fgx cerr<<"--------------"<<endl
    #define dgx cerr<<"=============="<<endl
    
    using namespace std;
    int to[maxn<<1],nxt[maxn<<1],hd[maxn],F[maxn][20];
    int tr[maxn<<4],mx[maxn<<4],ls[maxn<<4],rs[maxn<<4];
    int ans[maxn],rt[maxn],cnt,tot,dep[maxn],N=100000;
    
    inline int read(){
        int x=0,f=1; char c=getchar();
        for(;!isdigit(c);c=getchar()) if(c=='-') f=-1;
        for(;isdigit(c);c=getchar()) x=x*10+c-'0';
        return x*f;
    }
    
    inline void addedge(int u,int v){
        to[++cnt]=v,nxt[cnt]=hd[u],hd[u]=cnt;
        to[++cnt]=u,nxt[cnt]=hd[v],hd[v]=cnt;
    }
    
    inline void dfs(int u,int fa){
        F[u][0]=fa,dep[u]=dep[fa]+1;
        for(int i=1;i<20;i++) F[u][i]=F[F[u][i-1]][i-1];
        for(int i=hd[u];i;i=nxt[i]){
            int v=to[i];
            if(v!=fa) dfs(v,u);
        }
    }
    
    inline int lca(int u,int v){
        if(dep[u]>dep[v]) swap(u,v);
        for(int i=19;i>=0;i--)
            if(dep[F[v][i]]>=dep[u])
                v=F[v][i];
        if(u==v) return u;
        for(int i=19;i>=0;i--)
            if(F[u][i]!=F[v][i])
                u=F[u][i],v=F[v][i];
        return F[u][0];
    }
    
    inline void pushup(int k){
        if(tr[ls[k]]>=tr[rs[k]]) tr[k]=tr[ls[k]],mx[k]=mx[ls[k]];
        else tr[k]=tr[rs[k]],mx[k]=mx[rs[k]]; 
    }
    
    inline int add(int x,int y,int l,int r,int k){
        if(!k) k=++tot;
        if(l==r){tr[k]+=y,mx[k]=l;return k;}
        int mid=l+r>>1;
        if(x<=mid) ls[k]=add(x,y,l,mid,ls[k]); 
        else rs[k]=add(x,y,mid+1,r,rs[k]);
        pushup(k); return k;
    }
    
    inline int merge(int l,int r,int u,int v){
        if(!u || !v) return u|v;
        if(l==r){tr[u]+=tr[v],mx[u]=l;return u;}
        int mid=l+r>>1;
        ls[u]=merge(l,mid,ls[u],ls[v]);
        rs[u]=merge(mid+1,r,rs[u],rs[v]);
        pushup(u); return u;
    }
    
    inline void Dfs(int u,int fa){
        for(int i=hd[u];i;i=nxt[i]){
            int v=to[i];
            if(v==fa) continue;
            Dfs(v,u);
            rt[u]=merge(1,N,rt[u],rt[v]);
        }
        ans[u]=(tr[rt[u]]==0)?0:mx[rt[u]];
    }
    
    int main(){
        int n=read(),m=read();
        for(int i=1;i<n;i++){
            int u=read(),v=read();
            addedge(u,v);
        }
        dfs(1,0);
        for(int i=1;i<=m;i++){
            int u=read(),v=read(),w=read(),l=lca(u,v);
            rt[u]=add(w,1,1,N,rt[u]);
            rt[v]=add(w,1,1,N,rt[v]);
            rt[l]=add(w,-1,1,N,rt[l]);
            rt[F[l][0]]=add(w,-1,1,N,rt[F[l][0]]);
        }
        Dfs(1,0);
        for(int i=1;i<=n;i++) cout<<ans[i]<<endl;
        return 0;
    }
    线段树合并

    线段树分治:

    大概是给你若干个只在时间$[l,r]$内生效的操作,求每个时间的状态。

    那么以时间为下标建立线段树,把每个操作视为区间操作。

    一般会写成标记永久化的形式。复杂度$O(nlog{n})$。

    #include<bits/stdc++.h>
    #define maxn 500005
    #define maxm 500005
    #define inf 0x7fffffff
    #define ll long long
    #define rint register ll
    #define debug(x) cerr<<#x<<": "<<x<<endl
    #define fgx cerr<<"--------------"<<endl
    #define dgx cerr<<"=============="<<endl
    
    using namespace std;
    ll ans[maxn],tr[maxn<<2],num[maxn<<2];
    ll L[maxn],R[maxn],val[maxn],n,mod;
    
    inline ll read(){
        ll x=0,f=1; char c=getchar();
        for(;!isdigit(c);c=getchar()) if(c=='-') f=-1;
        for(;isdigit(c);c=getchar()) x=x*10+c-'0';
        return x*f;
    }
    
    inline void build(int l,int r,int k){
        tr[k]=1; if(l==r) return;
        int mid=l+r>>1;
        build(l,mid,k<<1),build(mid+1,r,k<<1|1);
    }
    
    inline void mul(ll x,ll y,ll z,ll l,ll r,ll k){
        if(x<=l && r<=y){tr[k]=tr[k]*z%mod;return;}
        ll mid=l+r>>1;
        if(x<=mid) mul(x,y,z,l,mid,k<<1);
        if(y>mid) mul(x,y,z,mid+1,r,k<<1|1);
    }
    
    inline void solve(ll l,ll r,ll v,ll k){
        num[k]=tr[k]*v%mod;
        if(l==r){ans[l]=num[k];return;}
        ll mid=l+r>>1;
        solve(l,mid,num[k],k<<1);
        solve(mid+1,r,num[k],k<<1|1); 
    }
    
    int main(){
        ll T=read();
        while(T--){
            n=read(),mod=read();
            for(ll i=1;i<=n;i++){
                ll op=read(),m=read();
                if(op==1) L[i]=i,R[i]=n,val[i]=m;
                else L[i]=R[i]=val[i]=0,R[m]=i-1;
            }
            build(1,n,1);
            for(ll i=1;i<=n;i++){
                //cout<<L[i]<<" "<<R[i]<<" "<<val[i]<<endl;
                if(val[i]) mul(L[i],R[i],val[i],1,n,1);
            }
            solve(1,n,1,1);
            for(ll i=1;i<=n;i++)
                printf("%lld
    ",ans[i]);
        } 
        return 0;
    }
    线段树分治
  • 相关阅读:
    小程序
    wepy
    html5 +css3 点击后水波纹扩散效果 兼容移动端
    vue+element 切换正式和测试环境
    Nuxt
    vue相关安装命令
    【react】--------------配置react项目根路径-------------【劉】
    【Android】--------------高版本http请求错误-------------【劉】
    【react-native】--------------检测SIM卡是否安装-------------【劉】
    【javascript】--------------http-------------【劉】
  • 原文地址:https://www.cnblogs.com/YSFAC/p/13068359.html
Copyright © 2011-2022 走看看