首页 > 其他分享 >线段树合并/分裂

线段树合并/分裂

时间:2023-05-02 18:11:05浏览次数:36  
标签:return val rs int 合并 线段 tree mid 分裂

你说的对,但是你理应会动态开点线段树是什么东西。

合并很简单,两棵线段树一块搜,然后逐个节点合并。

分裂的话可以按照 FHQ Treap 的方法。假如我们将前 \(k\) 小和后边分开成 \(x,y\),首先看左子树,如果比 \(k\) 大那右子树给 \(y\),递归左子树,反之左子树给 \(x\),递归右子树。

真没啥好说的,存个板子得了。值得注意的其实是垃圾回收怎么写,以前没写过。

#include <cstdio>
#include <algorithm>
#include <iostream>
#include <cstring>
#include <vector>
#define int long long
#define lson tree[rt].ls
#define rson tree[rt].rs
using namespace std;
int n,m,cnt,num,buf[200010<<5];
struct node{
    int ls,rs,val;
}tree[200010<<5];
int t,rt[200010];
int New(){
    return cnt?buf[cnt--]:++t;
}
void del(int x){
    buf[++cnt]=x;tree[x].ls=tree[x].rs=tree[x].val=0;
}
void pushup(int rt){
    tree[rt].val=tree[lson].val+tree[rson].val;
}
void update(int &rt,int L,int R,int pos,int val){
    if(!rt)rt=New();
    if(L==R){
        tree[rt].val+=val;return;
    }
    int mid=(L+R)>>1;
    if(pos<=mid)update(lson,L,mid,pos,val);
    else update(rson,mid+1,R,pos,val);
    pushup(rt);
}
int query(int rt,int L,int R,int l,int r){
    if(l<=L&&R<=r)return tree[rt].val;
    int mid=(L+R)>>1,val=0;
    if(l<=mid)val+=query(lson,L,mid,l,r);
    if(mid<r)val+=query(rson,mid+1,R,l,r);
    return val;
}
int querykth(int rt,int L,int R,int k){
    if(L==R)return L;
    int mid=(L+R)>>1;
    if(tree[lson].val>=k)return querykth(lson,L,mid,k);
    else return querykth(rson,mid+1,R,k-tree[lson].val);
}
int merge(int x,int y,int l,int r){
    if(!x||!y)return x|y;
    if(l==r){
        tree[x].val+=tree[y].val;del(y);
        return x;
    }
    int mid=(l+r)>>1;
    tree[x].ls=merge(tree[x].ls,tree[y].ls,l,mid);
    tree[x].rs=merge(tree[x].rs,tree[y].rs,mid+1,r);
    pushup(x);del(y);
    return x;
}
void split(int x,int &y,int k){
    if(!x)return;
    y=New();
    int val=tree[tree[x].ls].val;
    if(k>val)split(tree[x].rs,tree[y].rs,k-val);
    else swap(tree[x].rs,tree[y].rs);
    if(k<val)split(tree[x].ls,tree[y].ls,k);
    tree[y].val=tree[x].val-k;tree[x].val=k;
}
signed main(){
    scanf("%lld%lld",&n,&m);
    for(int i=1;i<=n;i++){
        int x;scanf("%lld",&x);
        update(rt[1],1,n,i,x);
    }
    num=1;
    while(m--){
        int od,p,x,y;scanf("%lld",&od);
        if(od==0){
            scanf("%lld%lld%lld",&p,&x,&y);
            int k1=query(rt[p],1,n,1,y),k2=query(rt[p],1,n,x,y);
            int tmp=0;
            split(rt[p],rt[++num],k1-k2);
            split(rt[num],tmp,k2);
            rt[p]=merge(rt[p],tmp,1,n);
        }
        else if(od==1){
            scanf("%lld%lld",&x,&y);
            rt[x]=merge(rt[x],rt[y],1,n);
        }
        else if(od==2){
            scanf("%lld%lld%lld",&p,&x,&y);
            update(rt[p],1,n,y,x);
        }
        else if(od==3){
            scanf("%lld%lld%lld",&p,&x,&y);
            printf("%lld\n",query(rt[p],1,n,x,y));
        }
        else{
            scanf("%lld%lld",&p,&x);
            if(tree[rt[p]].val<x)puts("-1");
            else printf("%lld\n",querykth(rt[p],1,n,x));
        }
    }
    return 0;
}

标签:return,val,rs,int,合并,线段,tree,mid,分裂
From: https://www.cnblogs.com/gtm1514/p/17368010.html

相关文章

  • 字典合并;函数返回值同时用于判断与输出
    1#普通字典update,与Counterupdate不同2d1={"1":2,"2":2}3d2={"1":1,"2":2}4print(d2)5#{'1':1,'2':2}6d2.update(d1)7print(d2)8#{'1':2,'2':2}9fromcollectio......
  • Halcon轮廓的分割,合并及圆&矩形&线拟合
    变换平滑轮廓:smooth_contours算子:smooth_contours_xld(Contours : SmoothedContours : NumRegrPoints :)示例:smooth_contours_xld(Border,SmoothedContours,11)Border(输入对象):输入轮廓对象SmoothedContours(输出对象):输出平滑后的轮廓11(输入控制参数):数值越大越平滑......
  • Halcon轮廓的分割,合并及圆&矩形&线拟合
    变换 平滑轮廓:smooth_contours算子:smooth_contours_xld(Contours : SmoothedContours : NumRegrPoints :)示例:smooth_contours_xld(Border,SmoothedContours,11)Border(输入对象):输入轮廓对象SmoothedContours(输出对象):输出平滑后的轮廓11(输入控制参数):数值越大越平滑形状变换......
  • CF 1709E XOR Tree(树上启发式合并)
    题目链接:https://codeforces.com/contest/1709/problem/E解题思路:定义sum(x,y)为x→y路径上的点的异或和,dx 为x→root路径上的点的异或和。对于一个点权树,sum(x,y)=dx ^dy ^vallca(x,y)。考虑修改一个点,可以将它改为一个很大的2为底数的幂,则经过此点的所有的不合......
  • 树上启发式合并学习笔记
    最近几天了解到一个很神奇的算法——dsuontree,看上去没多快实际上很快,这叫低调。好久不更了,至于反演,5月再更吧,4月的最后一天分享一下dsuontree。顺便闲话一句,4/26是我生日,也是历史二模。重链剖分dsuontree这类dsuontree适用于多次询问,每次询问需要$O(子树大小)......
  • 区间不同数的个数 二维数点 扫描线 可持久化线段树
    二维数点,对于询问的\([l,r]\)区间我们只需要统计有多少个数上一次出现的位置\(pos\)满足\(pos\leql\),即可。template<classT>structBIT{Tc[N];intsize;voidresize(ints){size=s;}Tquery(intx){//1...xassert(x<=size);......
  • Markdown表格-换行、合并单元格
    1.表格中对其、换行处理1.1一般我们都会这样用表格如下:|排名|姓名||--|--||第一名|隔壁老王||第二名|隔壁小王、隔壁小小王|实现效果图:排名姓名第一名隔壁老王第二名隔壁小王、隔壁小小王1.2当然这里也可以通过设置|:--|左对齐,|--:|右对齐比如下面的......
  • 合并与最高级别
    问题:部门和项目名称相同的整理成一行,名称合并,工程级别显示最高级别。函数公式解决:部门与项目名称的唯一值:{=UNIQUE(B2:C5)}合并名称:{=TEXTJOIN("、",,FILTER(D$2:D$5,(B$2:B$5=G2)*(C$2:C$5=H2)))}工程最高级别:{=MAX((B$2:B$5=G2)*(C$2:C$5=H2)*--SUBSTITUTE(E$2:E$5,"......
  • CF600E Lomsat gelral(树上启发式合并)
    题目链接:https://codeforces.com/problemset/problem/600/E这是一道树上启发式合并的题,就只是在模板的基础上稍微变化了一下解题思路:我们需要计算当前u节点的答案,要计算加入非重链节点对此答案的影响,在计算加入节点对ans影响的时候,遍历u除了重链外的所有子树节点(因为重链部分的......
  • C#:使用ffmpeg将图片合并成视频
    最近遇到公司的一个项目,需要将多张图片合并成一个播放的视频,找了很多资料和尝试了工具,遇到很多的坑,这里记下来,希望大家也能顺利解决遇到的问题。合并视频,主要可以借用OpenCV和 ffmpeg,这里是尝试用ffmpeg.exe的工具去实现图片文件合并成视频。输入存储视频文件的路......