• 线段树合并学习笔记


    线段树合并用于解决一些需要将两颗线段树合并的题目

    常见于一些子树处理的题目。

    动态开点,记录左右子树。

    不得不说,merge的代码像极了FHQtreap

    inline int merge(int a,int b,int x,int y){
          if(!a)return b;
          if(!b)return a;
          if(x==y)/*do whatever you need and return a*/
          int mid=(x+y)>>1;
          tr[a].l=merge(tr[a].l,tr[b].l,x,mid);
          tr[a].r=merge(tr[a].r,tr[b].r,mid+1,y);
          pushup(a);
          return a;  
    }

    然后是更新,其实代码很好写……

    inline void update(int &now,int l,int r,int x){
            if(!now)now=++cnt;
            if(l==r)/*do whatever you need*/
            int mid=(l+r)>>1;
            if(mid>=x)update(tr[now].l,l,mid,x);
            else update(tr[now].r,mid+1,r,x);
            pushup(now);
    }

    然后推荐几道例题:

    1.CF600E

    思路:对于每一个节点,它的线段树等于所有子节点线段树的合并在加上它自己。

    代码如下:

    #include<bits/stdc++.h>
    using namespace std;
    #define int long long
    const int maxn=2*1e5+10;
    inline int read(){
        int x=0,f=1;char c=getchar();
        while(c<'0'||c>'9'){if(c=='-')f=-1;char c=getchar();}
        while(c>='0'&&c<='9'){x=(x<<1)+(x<<3)+c-'0';c=getchar();}
        return x*f;
    }
    struct node{
        int l,r,val,sum,ans;
    }tr[maxn*25];
    int n,c[maxn],root[maxn],cnt,ans[maxn];
    int beg[maxn],nex[maxn<<1],to[maxn<<1],e;
    inline void add(int x,int y){
        e++;nex[e]=beg[x];
        beg[x]=e;to[e]=y;
    }
    inline void pushup(int now){
        int l=tr[now].l,r=tr[now].r;
        if(tr[l].sum>tr[r].sum){
            tr[now].ans=tr[l].ans;
            tr[now].sum=tr[l].sum;
            tr[now].val=tr[l].val;
        }
        if(tr[l].sum<tr[r].sum){
            tr[now].ans=tr[r].ans;
            tr[now].sum=tr[r].sum;
            tr[now].val=tr[r].val;
        }
        if(tr[l].sum==tr[r].sum){
            tr[now].ans=tr[l].ans+tr[r].ans;
            tr[now].sum=tr[l].sum;
            tr[now].val=tr[l].val;
        }
    }
    inline void update(int &now,int l,int r,int x){
        if(!now)now=++cnt;
        if(l==r){
            tr[now].val=l;
            tr[now].sum++;
            tr[now].ans=l;
            return;
        }
        int mid=(l+r)>>1;
        if(mid>=x)update(tr[now].l,l,mid,x);
        else update(tr[now].r,mid+1,r,x);
        pushup(now);
    }
    inline int merge(int a,int b,int l,int r){
        if(!a)return b;
        if(!b)return a;
        if(l==r){
            tr[a].ans=tr[a].val=l;
            tr[a].sum+=tr[b].sum;
            return a;
        }
        int mid=(l+r)>>1;
        tr[a].l=merge(tr[a].l,tr[b].l,l,mid);
        tr[a].r=merge(tr[a].r,tr[b].r,mid+1,r);
        pushup(a);
        return a;
    }
    inline void dfs(int fa,int x){
        for(int i=beg[x];i;i=nex[i]){
            int t=to[i];
            if(t==fa)continue;
            dfs(x,t);
            merge(root[x],root[t],1,n);
        }
        update(root[x],1,n,c[x]);
        ans[x]=tr[root[x]].ans;
    }
    signed main(){
        n=read();
        for(int i=1;i<=n;i++){
            c[i]=read();
            root[i]=i;
        }
        int x,y;
        for(int i=1;i<n;i++){
            x=read(),y=read();
            add(x,y),add(y,x);
        }
        cnt=n;
        dfs(0,1);
        for(int i=1;i<=n;i++)
            printf("%lld ",ans[i]);
        puts("");
        return 0;
    } 

    2.P3605

    思路:1.首先离散化(常规套路);

          2.建权值线段树;

          3.合并子节点(也是常规套路);

    代码如下:

    //p3605,线段树合并,score=100
    #include<bits/stdc++.h>
    using namespace std;
    const int maxn=1e5+10;
    int n,p[maxn],tmp[maxn],ans[maxn],rt[maxn],cnt;
    int beg[maxn],nex[maxn<<1],to[maxn<<1],e;
    inline int read(){
        int x=0,f=1;char c=getchar();
        while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();}
        while(c>='0'&&c<='9'){x=(x<<1)+(x<<3)+c-'0';c=getchar();}
        return x*f;
    }
    inline void add(int x,int y){
        e++;nex[e]=beg[x];
        beg[x]=e;to[e]=y;
    }
    struct node{
        int l,r,val;
    }tr[maxn*50];
    inline int query(int h,int l,int r,int x,int y){
        if(l>y||r<x)return 0;
        if(l>=x&&r<=y)return tr[h].val;
        int mid=(l+r)>>1;
        return query(tr[h].l,l,mid,x,y)+query(tr[h].r,mid+1,r,x,y);
    }
    inline void update(int &now,int l,int r,int x){
        if(!now)now=++cnt;
        if(l==r){
            tr[now].val++;
            return;
        }
        int mid=(l+r)>>1;
        if(mid>=x)update(tr[now].l,l,mid,x);
        else update(tr[now].r,mid+1,r,x);
        tr[now].val=tr[tr[now].l].val+tr[tr[now].r].val;
    } 
    inline int merge(int a,int b,int l,int r){
        if(!a)return b;
        if(!b)return a;
        if(l==r){
            tr[a].val+=tr[b].val;
            return a;
        }
        int mid=(l+r)>>1;
        tr[a].l=merge(tr[a].l,tr[b].l,l,mid);
        tr[a].r=merge(tr[a].r,tr[b].r,mid+1,r);
        tr[a].val=tr[tr[a].l].val+tr[tr[a].r].val;
        return a;
    }
    inline void dfs(int x,int fa){
        for(int i=beg[x];i;i=nex[i]){
            int t=to[i];
            if(t==fa)continue;
            dfs(t,x);
            merge(rt[x],rt[t],1,n);
        }
        ans[x]=query(rt[x],1,n,p[x],n);
        update(rt[x],1,n,p[x]);
    }
    int main(){
        n=read();
        for(int i=1;i<=n;i++){
            tmp[i]=p[i]=read();
            rt[i]=i;
        }
        sort(tmp+1,tmp+1+n);
        for(int i=1;i<=n;i++)
            p[i]=lower_bound(tmp+1,tmp+1+n,p[i])-tmp;
        int x;
        for(int i=2;i<=n;i++){
            x=read();
            add(i,x),add(x,i);
        }
        cnt=n;
        dfs(1,0);
        for(int i=1;i<=n;i++)
            printf("%d
    ",ans[i]);
        return 0;
    }

    3.雨天的尾巴

    有了线段树合并的基础后,很容易想到差分最后线段树合并。

    这道题跟hdu上的relief grain是重题,然而我们老师却把那道题当做树剖的练手题给我们。

    害得我想了好久……

    代码如下:

    //p3605,线段树合并,score=100
    #include<bits/stdc++.h>
    using namespace std;
    const int maxn=1e5+10;
    int n,p[maxn],tmp[maxn],ans[maxn],rt[maxn],cnt;
    int beg[maxn],nex[maxn<<1],to[maxn<<1],e;
    inline int read(){
        int x=0,f=1;char c=getchar();
        while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();}
        while(c>='0'&&c<='9'){x=(x<<1)+(x<<3)+c-'0';c=getchar();}
        return x*f;
    }
    inline void add(int x,int y){
        e++;nex[e]=beg[x];
        beg[x]=e;to[e]=y;
    }
    struct node{
        int l,r,val;
    }tr[maxn*50];
    inline int query(int h,int l,int r,int x,int y){
        if(l>y||r<x)return 0;
        if(l>=x&&r<=y)return tr[h].val;
        int mid=(l+r)>>1;
        return query(tr[h].l,l,mid,x,y)+query(tr[h].r,mid+1,r,x,y);
    }
    inline void update(int &now,int l,int r,int x){
        if(!now)now=++cnt;
        if(l==r){
            tr[now].val++;
            return;
        }
        int mid=(l+r)>>1;
        if(mid>=x)update(tr[now].l,l,mid,x);
        else update(tr[now].r,mid+1,r,x);
        tr[now].val=tr[tr[now].l].val+tr[tr[now].r].val;
    } 
    inline int merge(int a,int b,int l,int r){
        if(!a)return b;
        if(!b)return a;
        if(l==r){
            tr[a].val+=tr[b].val;
            return a;
        }
        int mid=(l+r)>>1;
        tr[a].l=merge(tr[a].l,tr[b].l,l,mid);
        tr[a].r=merge(tr[a].r,tr[b].r,mid+1,r);
        tr[a].val=tr[tr[a].l].val+tr[tr[a].r].val;
        return a;
    }
    inline void dfs(int x,int fa){
        for(int i=beg[x];i;i=nex[i]){
            int t=to[i];
            if(t==fa)continue;
            dfs(t,x);
            merge(rt[x],rt[t],1,n);
        }
        ans[x]=query(rt[x],1,n,p[x],n);
        update(rt[x],1,n,p[x]);
    }
    int main(){
        n=read();
        for(int i=1;i<=n;i++){
            tmp[i]=p[i]=read();
            rt[i]=i;
        }
        sort(tmp+1,tmp+1+n);
        for(int i=1;i<=n;i++)
            p[i]=lower_bound(tmp+1,tmp+1+n,p[i])-tmp;
        int x;
        for(int i=2;i<=n;i++){
            x=read();
            add(i,x),add(x,i);
        }
        cnt=n;
        dfs(1,0);
        for(int i=1;i<=n;i++)
            printf("%d
    ",ans[i]);
        return 0;
    }

    深深地感到自己的弱小。

  • 相关阅读:
    opencv掩模操作
    cvtColor()学习
    opencv中mat类介绍
    c++中的stl
    opencv3中SurfFeatureDetector、SurfDescriptorExtractor、BruteForceMatcher的使用
    CUDA学习
    visual studio + opencv + contrib
    11.14/11.15 Apache和PHP结合 11.16/11.17 Apache默认虚拟主机
    11.10/11.11/11.12 安装PHP5 11.13 安装PHP7
    11.6 MariaDB安装 11.7/11.8/11.9 Apache安装
  • 原文地址:https://www.cnblogs.com/syzf2222/p/12584672.html
Copyright © 2020-2023  润新知