【题解】P2710 数列

区间操作集大成者……?

可能吧……

by某位不愿意透露姓名的巨学
***
本题需要实现:

  • INSERT
  • DELETE
  • REVERSE
  • MAKE-SAME
  • GET-SUM
  • GET
  • MAX-SUM

共七个操作

全部操作都涉及到序列

于是我们考虑使用splay或者FHQ-treap实现

这里使用FHQ-treap
***
前置芝士

  • FHQ-treap

蛤?不会?左转度娘/必应娘/谷歌娘

  • 区间翻转

左转P3391题解区,包教包会,不会不要钱本来就不要钱吧

  • 最大子段和

左转P4513
***
非必要

  • 笛卡尔树建树

实际上不用这个方法用暴力插入也能过,但可能需要卡卡常

  • 卡常技巧
    ***
    0.初始定义
struct note {
    int val;//节点权值
    int rd;//优先值
    int siz;//子树大小
    int ch[2];//左右儿子
    int tag;//翻转标记
    int cvr;//make-same标记
    int sum;//区间和
    int lmax,rmax,mmax;//最大子段和
    note() {
        ch[0]=ch[1]=val=siz=sum=tag=0;
        cvr=inf;
    }
    inline void clear() {
        ch[0]=ch[1]=val=siz=sum=tag=0;
        cvr=inf;
    }
};

-1.信息上传,标记下放

inline void up(int o) {
    int ls=t[o].ch[0],rs=t[o].ch[1];
    t[o].siz=t[ls].siz+t[rs].siz+1;
    t[o].sum=t[o].val+t[ls].sum+t[rs].sum;
    t[o].lmax=max(0,max(t[ls].lmax,t[ls].sum+t[rs].lmax+t[o].val));
    t[o].rmax=max(0,max(t[rs].rmax,t[rs].sum+t[ls].rmax+t[o].val));
    t[o].mmax=max(t[o].val,t[ls].rmax+t[rs].lmax+t[o].val);
    if (ls) {
        t[o].mmax=max(t[o].mmax,t[ls].mmax);
    }
    if (rs) {
        t[o].mmax=max(t[o].mmax,t[rs].mmax);
    }
}
inline void flip(int o) {
    swap(t[o].ch[0],t[o].ch[1]);
    swap(t[o].lmax,t[o].rmax);
    t[o].tag^=1;
}
inline void cvr(int o,int val) {
    t[o].cvr=t[o].val=val;
    t[o].sum=t[o].siz*val;
    t[o].mmax=max(t[o].val,t[o].sum);
    t[o].lmax=t[o].rmax=max(0,t[o].sum);
}
inline void down(int o) {
    int ls=t[o].ch[0],rs=t[o].ch[1];
    if (t[o].tag) {
        if (ls) {
            flip(ls);
        }
        if (rs) {
            flip(rs);
        }
    }
    if (t[o].cvr!=inf) {
        if (ls) {
            cvr(ls,t[o].cvr);
        }
        if (rs) {
            cvr(rs,t[o].cvr);
        }
    }
    t[o].tag=0;
    t[o].cvr=inf;
}

1.插入操作

第一个要实现的操作,然而并不是最简单的

我们可以选择暴力插入,但……

这样子做的时间复杂度是O(qlogn)的,其中q为插入序列中数的个数

如何优化?

笛卡尔树建树!

自行度娘具体方法,这里直接给出代码

inline int build(int len,int a[]) {
    top=0;
    int temp=new_node(a[1]);
    stk[++top]=temp;
    for(int i=2;i<=len;i++) {
        int last=0;
        int cur=new_node(a[i]);
        while(top&&t[stk[top]].rd>t[cur].rd) {
            up(stk[top]);
            last=stk[top];
            stk[top--]=0;
        }
        t[cur].ch[0]=last;
        up(cur);
        if (top) {
            t[stk[top]].ch[1]=cur;
            up(stk[top]);
        }
        stk[++top]=cur;
    }
    while(top) {
        up(stk[top--]);
    }
    return stk[1];
}

返回的是新建树的根

有了这个函数,insert就非常好写了

inline void insert(int pos,int len,int a[]) {
    int root1=build(len,a);
    int x,y;
    split(root,pos,x,y);
    root=merge(merge(x,root1),y);
}

时间复杂度O(q+logn),其中q为序列中数的个数
***
2.delete操作

把要删除的区间提取出来直接中序历删除即可

注意垃圾回收

void recycle(int o) {
    int ls=t[o].ch[0],rs=t[o].ch[1];
    if (!o) {
        return;
    }
    if (ls) {
        recycle(ls);
    }
    trash.push(o);
    if (rs) {
        recycle(rs);
    }
}

inline void remove(int pos,int len) {
    int x,y,z,u;
    split(root,pos+len-1,x,y);
    split(x,pos-1,z,u);
    recycle(u);
    root=merge(z,y);
}

时间复杂度O(logn+q)
***
3.REVERSE操作

左转文艺平衡树

注意标记下放

inline void reverse(int pos,int len) {
    int x,y,z,u;
    split(root,pos+len-1,x,y);
    split(x,pos-1,z,u);
    t[u].tag^=1;
    swap(t[u].lmax,t[u].rmax);
    swap(t[u].ch[0],t[u].ch[1]);
    root=merge(merge(z,u),y);
    return;
}

时间复杂度O(logn)
***
4.MAKE-SAME操作

全场最烦操作(因为要手动更新

inline void cover(int pos,int len,int val) {
    int x,y,u,z;
    split(root,pos+len-1,x,y);
    split(x,pos-1,z,u);
    t[u].val=t[u].cvr=val;
    t[u].sum=val*t[u].siz;
    t[u].lmax=t[u].rmax=max(0,t[u].sum);
    t[u].mmax=max(t[u].val,t[u].sum);
    t[u].tag=0;
    root=merge(merge(z,u),y);
}

时间复杂度O(logn)
***
5.三大询问

因为代码都很无脑就放一起了

inline int get_sum(int pos,int len) {
    int x,y,z,u;
    split(root,pos+len-1,x,y);
    split(x,pos-1,z,u);
    int ans=t[u].sum;
    root=merge(merge(z,u),y);
    return ans;
}
inline int get_max_sum(int pos,int len) {
    int x,y,z,u;
    split(root,pos+len-1,x,y);
    split(x,pos-1,z,u);
    int ans=t[u].mmax;
    root=merge(merge(z,u),y);
    return ans;
}
inline int ask_point(int pos) {
    int x,y,z,u;
    split(root,pos,x,y);
    split(x,pos-1,z,u);
    int ans=t[u].val;
    root=merge(merge(z,u),y);
    return ans;
}

时间复杂度O(logn)
***
最后,让我们看看核心函数:merge和split

void split(int x,int k,int &a,int &b) {
    if (!x||!k) {
        a=0;
        b=x;
        return;
    }
    down(x);
    if (k>t[t[x].ch[0]].siz) {
        a=x;
        split(t[x].ch[1],k-t[t[x].ch[0]].siz-1,t[x].ch[1],b);
        up(x);
    } else {
        b=x;
        split(t[x].ch[0],k,a,t[x].ch[0]);
        up(x);
    }
}
int merge(int x,int y) {
    if (x) {
        down(x);
    }
    if (y) {
        down(y);
    }
    if (!x||!y) {
        return x^y;
    }
    if (t[x].rd<t[y].rd) {
        t[x].ch[1]=merge(t[x].ch[1],y);
        up(x);
        return x;
    } else {
        t[y].ch[0]=merge(x,t[y].ch[0]);
        up(y);
        return y;
    }
}

遵循原则:用时间换安全

具体来讲,在写这两个函数的时候,能上传下放就上传下放,保障安全
***
最后的最后,一点个人感想

前前后后调了半个寒假,还是很有收获的

up,down,merge,split四个核心函数一定要好好理解,不然一出bug就……

放总体代码 我知道你们只想看这个

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cstdlib>
#include <ctime>
#include <queue>
#include <string>
using namespace std;

inline int Random() {
    return (rand()<<15)|rand();
}

inline void read(int &x) {
    x=0;
    int f=1;
    char ch=getchar();
    while(ch<'0'||ch>'9') {
        if (ch=='-') {
            f=-1;
        }
        ch=getchar();
    }
    while(ch>='0'&&ch<='9') {
        x=(x<<3)+(x<<1)+ch-'0';
        ch=getchar();
    }
    x*=f;
}

queue<int> trash;//????????
int root;//???????
const int inf=2e9;

struct note {
    int val;//??
    int rd;//???????
    int siz;//?????
    int ch[2];//???????
    int tag;//????????
    int cvr;//????????
    int sum;//???
    int lmax,rmax,mmax;//??????
    note() {
        ch[0]=ch[1]=val=siz=sum=tag=0;
        cvr=inf;
    }
    inline void clear() {
        ch[0]=ch[1]=val=siz=sum=tag=0;
        cvr=inf;
    }
};

int stk[500010],top;

struct fhq_treap {
    note t[200010];
    int cnt;
    //??????
    inline int q_malloc() {
        int x;
        return (!trash.empty()) ? (x=trash.front(),t[x].clear() , trash.pop() , x) : (++cnt);
    }
    //??????
    inline int new_node(int val) {
        int x=q_malloc();
        t[x].val=t[x].sum=t[x].mmax=val;
        t[x].lmax=t[x].rmax=max(0,val);
        t[x].rd=Random();
        t[x].siz=1;
        return x;
    }
    //?????
    inline void up(int o) {
        int ls=t[o].ch[0],rs=t[o].ch[1];
        t[o].siz=t[ls].siz+t[rs].siz+1;
        t[o].sum=t[o].val+t[ls].sum+t[rs].sum;
        t[o].lmax=max(0,max(t[ls].lmax,t[ls].sum+t[rs].lmax+t[o].val));
        t[o].rmax=max(0,max(t[rs].rmax,t[rs].sum+t[ls].rmax+t[o].val));
        t[o].mmax=max(t[o].val,t[ls].rmax+t[rs].lmax+t[o].val);
        if (ls) {
            t[o].mmax=max(t[o].mmax,t[ls].mmax);
        }
        if (rs) {
            t[o].mmax=max(t[o].mmax,t[rs].mmax);
        }
    }
    //????
    inline void flip(int o) {
        swap(t[o].ch[0],t[o].ch[1]);
        swap(t[o].lmax,t[o].rmax);
        t[o].tag^=1;
    }
    //????????????
    inline void cvr(int o,int val) {
        t[o].cvr=t[o].val=val;
        t[o].sum=t[o].siz*val;
        t[o].mmax=max(t[o].val,t[o].sum);
        t[o].lmax=t[o].rmax=max(0,t[o].sum);
    }
    //?????
    inline void down(int o) {
        int ls=t[o].ch[0],rs=t[o].ch[1];
        if (t[o].tag) {
            if (ls) {
                flip(ls);
            }
            if (rs) {
                flip(rs);
            }
        }
        if (t[o].cvr!=inf) {
            if (ls) {
                cvr(ls,t[o].cvr);
            }
            if (rs) {
                cvr(rs,t[o].cvr);
            }
        }
        t[o].tag=0;
        t[o].cvr=inf;
    }
    //???
    //len:??????a[]:?????????
    //?????????
    inline int build(int len,int a[]) {
        top=0;
        int temp=new_node(a[1]);
        stk[++top]=temp;
        for(int i=2;i<=len;i++) {
            int last=0;
            int cur=new_node(a[i]);
            while(top&&t[stk[top]].rd>t[cur].rd) {
                up(stk[top]);
                last=stk[top];
                stk[top--]=0;
            }
            t[cur].ch[0]=last;
            up(cur);
            if (top) {
                t[stk[top]].ch[1]=cur;
                up(stk[top]);
            }
            stk[++top]=cur;
        }
        while(top) {
            up(stk[top--]);
        }
        return stk[1];
    }
    //??????
    //a???????
    //b???????
    //x???????????
    //k??????????
    void split(int x,int k,int &a,int &b) {
        if (!x||!k) {
            a=0;
            b=x;
            return;
        }
        down(x);
        if (k>t[t[x].ch[0]].siz) {
            a=x;
            split(t[x].ch[1],k-t[t[x].ch[0]].siz-1,t[x].ch[1],b);
            up(x);
        } else {
            b=x;
            split(t[x].ch[0],k,a,t[x].ch[0]);
            up(x);
        }
    }
    //??????
    //x??????????
    //y??????????
    int merge(int x,int y) {
        if (x) {
            down(x);
        }
        if (y) {
            down(y);
        }
        if (!x||!y) {
            return x^y;
        }
        if (t[x].rd<t[y].rd) {
            t[x].ch[1]=merge(t[x].ch[1],y);
            up(x);
            return x;
        } else {
            t[y].ch[0]=merge(x,t[y].ch[0]);
            up(y);
            return y;
        }
    }
    //?????
    void recycle(int o) {
        int ls=t[o].ch[0],rs=t[o].ch[1];
        if (!o) {
            return;
        }
        if (ls) {
            recycle(ls);
        }
        trash.push(o);
        if (rs) {
            recycle(rs);
        }
    }
    //?????
    //pos??????
    //len????????
    //a[]???
    inline void insert(int pos,int len,int a[]) {
        int root1=build(len,a);
        int x,y;
        split(root,pos,x,y);
        root=merge(merge(x,root1),y);
    }
    //??????
    //pos???????????
    //len????????
    inline void remove(int pos,int len) {
        int x,y,z,u;
        split(root,pos+len-1,x,y);
        split(x,pos-1,z,u);
        recycle(u);
        root=merge(z,y);
    }
    //??????
    //pos???????????
    //len????????
    inline void reverse(int pos,int len) {
        int x,y,z,u;
        split(root,pos+len-1,x,y);
        split(x,pos-1,z,u);
        t[u].tag^=1;
        swap(t[u].lmax,t[u].rmax);
        swap(t[u].ch[0],t[u].ch[1]);
        root=merge(merge(z,u),y);
        return;
    }
    //?????
    //pos??????????
    //len???????
    //val?????
    inline void cover(int pos,int len,int val) {
        int x,y,u,z;
        split(root,pos+len-1,x,y);
        split(x,pos-1,z,u);
        t[u].val=t[u].cvr=val;
        t[u].sum=val*t[u].siz;
        t[u].lmax=t[u].rmax=max(0,t[u].sum);
        t[u].mmax=max(t[u].val,t[u].sum);
        t[u].tag=0;
        root=merge(merge(z,u),y);
    }
    inline int get_sum(int pos,int len) {
        int x,y,z,u;
        split(root,pos+len-1,x,y);
        split(x,pos-1,z,u);
        int ans=t[u].sum;
        root=merge(merge(z,u),y);
        return ans;
    }
    inline int get_max_sum(int pos,int len) {
        int x,y,z,u;
        split(root,pos+len-1,x,y);
        split(x,pos-1,z,u);
        int ans=t[u].mmax;
        root=merge(merge(z,u),y);
        return ans;
    }
    inline int ask_point(int pos) {
        int x,y,z,u;
        split(root,pos,x,y);
        split(x,pos-1,z,u);
        int ans=t[u].val;
        root=merge(merge(z,u),y);
        return ans;
    }
};

fhq_treap ft;
int n,m;

inline void read_str(char p[]) {
    char ch=getchar();
    int len=0;
    while(!isalpha(ch)&&ch!='-') {
        ch=getchar();
    }
    while(isalpha(ch)||ch=='-') {
        p[len++]=ch;
        ch=getchar();
    }
}

int a[4000010];

int main() {
    srand((unsigned)time(0));
    read(n),read(m);
    for(int i=1;i<=n;i++) {
        read(a[i]);
    }
    root=ft.build(n,a);
    int pos,len,val;
    string s;
    for(int i=1;i<=m;i++) {
        cin>>s;
        if (s=="INSERT") {
            read(pos),read(len);
            for(int i=1;i<=len;i++) {
                read(a[i]);
            }
            ft.insert(pos,len,a);
        } else if(s=="DELETE") {
            read(pos),read(len);
            ft.remove(pos,len);
        } else if (s=="REVERSE") {
            read(pos),read(len);
            ft.reverse(pos,len);
        } else if (s=="MAKE-SAME") {
            read(pos),read(len),read(val);
            ft.cover(pos,len,val);
        } else if (s=="MAX-SUM"){
            read(pos),read(len);
            printf("%d\n",ft.get_max_sum(pos,len));
        } else if (s=="GET-SUM") {
            read(pos),read(len);
            printf("%d\n",ft.get_sum(pos,len));
        } else {
            read(pos);
            printf("%d\n",ft.ask_point(pos));
        }
    }
    return 0;
}

转载于:https://www.cnblogs.com/tt66ea-blog/p/10991879.html

【使用教程】 一、环境配置 1、建议下载anaconda和pycharm 在anaconda中配置好环境,然后直接导入到pycharm中,在pycharm中运行项目 anaconda和pycharm安装及环境配置参考网上博客,有很多博主介绍 2、在anacodna中安装requirements.txt中的软件包 命令为:pip install -r requirements.txt 或者改成清华源后再执行以上命令,这样安装要快一些 软件包都安装成功后才算成功 3、安装好软件包后,把anaconda中对应的python导入到pycharm中即可(不难,参考网上博客) 二、环境配置好后,开始训练(也可以训练自己数据集) 1、数据集准备 需要准备yolo格式的目标检测数据集,如果不清楚yolo数据集格式,或者有其他数据训练需求,请看博主yolo格式各种数据集集合链接:https://blog.csdn.net/DeepLearning_/article/details/127276492 里面涵盖了上百种yolo数据集,且在不断更新,基本都是实际项目使用。来自于网上收集、实际场景采集制作等,自己使用labelimg标注工具标注的。数据集质量绝对有保证! 本项目所使用的数据集,见csdn该资源下载页面中的介绍栏,里面有对应的下载链接,下载后可直接使用。 2、数据准备好,开始修改配置文件 参考代码中data文件夹下的banana_ripe.yaml,可以自己新建一个不同名称的yaml文件 train:训练集的图片路径 val:验证集的图片路径 names: 0: very-ripe 类别1 1: immature 类别2 2: mid-ripe 类别3 格式按照banana_ripe.yaml照葫芦画瓢就行,不需要过多参考网上的 3、修改train_dual.py中的配置参数,开始训练模型 方式一: 修改点: a.--weights参数,填入'yolov9-s.pt',博主训练的是yolov9-s,根据自己需求可自定义 b.--cfg参数,填入 models/detect/yolov9-c.yaml c.--data参数,填入data/banana_ripe.yaml,可自定义自己的yaml路径 d.--hyp参数,填入hyp.scratch-high.yaml e.--epochs参数,填入100或者200都行,根据自己的数据集可改 f.--batch-size参数,根据自己的电脑性能(显存大小)自定义修改 g.--device参数,一张显卡的话,就填0。没显卡,使用cpu训练,就填cpu h.--close-mosaic参数,填入15 以上修改好,直接pycharm中运行train_dual.py开始训练 方式二: 命令行方式,在pycharm中的终端窗口输入如下命令,可根据自己情况修改参数 官方示例:python train_dual.py --workers 8 --device 0 --batch 16 --data data/coco.yaml --img 640 --cfg models/detect/yolov9-c.yaml --weights '' --name yolov9-c --hyp hyp.scratch-high.yaml --min-items 0 --epochs 500 --close-mosaic 15 训练完会在runs/train文件下生成对应的训练文件及模型,后续测试可以拿来用。 三、测试 1、训练完,测试 修改detect_dual.py中的参数 --weights,改成上面训练得到的best.pt对应的路径 --source,需要测试的数据图片存放的位置,代码中的test_imgs --conf-thres,置信度阈值,自定义修改 --iou-thres,iou阈值,自定义修改 其他默认即可 pycharm中运行detect_dual.py 在runs/detect文件夹下存放检测结果图片或者视频 【备注】 1、该资源内项目代码都经过测试运行成功,功能ok的情况下才上传的,请放心下载使用!有问题请及时沟通交流。 2、适用人群:计算机相关专业(如计科、信息安全、数据科学与大数据技术、人工智能、通信、物联网、自动化、电子信息等)在校学生、专业老师或者企业员工下载使用。
本项目是一个基于SSM(Spring+SpringMVC+MyBatis)框架和Vue.js前端技术的二手手机回收平台系统。该系统旨在为二手手机回收提供一个便捷、高效的在线交易平台,同时确保交易的安全性和透明度。 在后台管理方面,系统提供了用户管理、商品管理、订单管理以及数据统计等功能。通过这些功能,管理员能够轻松地管理平台上的用户信息、审核商品发布、跟踪订单状态,并对平台的运营数据进行详细的分析。 在前端展示上,系统采用了Vue.js框架,实现了响应式的用户界面设计。用户可以通过直观的界面浏览商品、发布自己的二手手机信息、下订单以及查看交易记录。此外,系统还提供了搜索和筛选功能,帮助用户快速找到符合自己需求的商品。 技术实现上,后端使用了Java语言,结合Spring框架进行依赖注入和事务管理,SpringMVC负责处理Web请求,而MyBatis则用于数据库操作。前端则使用Vue.js进行页面渲染和交互逻辑处理,搭配Axios进行异步数据请求。 本项目的数据库设计充分考虑了数据的完整性和安全性,采用了关系型数据库MySQL进行数据存储。数据库表结构包括用户表、商品表、订单表等,确保了系统的高效运行和数据的一致性。 对于正在进行毕业设计的学生或需要项目实战练习的Java学习者来说,本项目提供了一个完整的技术栈和业务逻辑实现,可以作为学习和实践的良好参考。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值