Jamie and To-do List (主席树 详解)

题目链接

题意:

四种操作:

1. set s x 如果x不存在,将x插入,并设置其优先值为x,如果x存在,直接修改其优先值为x。

2. remove s 删除s

3. query s 询问优先值比s小的有多少个

4. undo d 撤销这次操作之前的d个操作

(感觉这题写好了,真能开发个自己的to-do list)

思路:

权值线段树r1,在优先级[1,1e9]的值域上,维护每个优先级出现的次数,单点修改+1/-1,区间查询[1,p-1],累加优先级比p小的字符串的个数

权值线段树r2,维护每个id的值域上,维护每个id的优先级,单点修改±dx,单点查询[id,id],直接返回叶子节点id的优先级

更详细的在注释里了

#include<bits/stdc++.h>
using namespace std;
const int N=1e5+5, INF=1e9+5;//INF 在[1,1e9]上建权值线段树
struct Node{
    int l,r,sum;
}hjt[N*100];//OMG 两棵主席树 其中一棵一次询问可能修改两次 注意空间
int cnt,r1[N],r2[N];//两棵主席树 r1[i]代表i优先级有多少个字符串(权值线段树) r2[id]代表id字符串对应的优先级是多少(这个其实也是权值,但维护的不是个数了,是该id值对应的优先级)
int top;
map<string,int>mp;
//Q:为什么不用建树呢? A:因为两棵都是权值线段树!初始版本就都是0,直到有新结点插入
//Q:为什么权值[1,1e9]可以建主席树呢? A:时间复杂度qlogx q=1e5 x=1e9 log(1e9)=30 总:3e6 可以哒
//Q:为什么是线段树? r2完全可以不用区间操作啊 A:为了迁就r1,r1不是要优先级查比p小的有多少个嘛...
void update(int l,int r,int pre,int &now,int pos, int num){
//当前区间[l,r] 历史版本pre 当前版本now 修改:pos位置上的数+val 
//对于r1树来说 这里维护的是权值 值域[1,1e9] pos位置的sum 代表pos数出现的次数
//对于r2树 范围[1,1e5](1e5个询问-可能的新串) pos串的sum 是它的优先级(修改优先级也是通过加减增量 不是直接改值)
    hjt[now=++cnt]=hjt[pre];//pre版本 复制到一块新的内存池 
    hjt[now].sum+=num;//? 权值 新插入一个数 sum++ 为什么在这里不在叶子节点里呢 //这个线段树上的累加 对r2树其实没有意义 但也没关系 反正r2树是单点查询 询问路径上的值都用不到 只会用到叶子节点
    if(l==r) return;
    int m=l+r>>1;
    if(pos<=m) update(l,m,hjt[pre].l,hjt[now].l,pos,num);
    else update(m+1,r,hjt[pre].r,hjt[now].r,pos,num);
//Q: 话说,这个主席树的hjt[now].l... 这个 .l .r 是多少啊,从来没有给节点的 .l .r赋过值啊...
//A: 额 假如第一次操作set 5 2,[1,1e9]的区间不断二分,5最终会找到它的位置,在找到5之前,0号主席树、1号主席树的所有节点的l、r都是0(因为0号初始都是0,1号复制0号的),
//到了5叶子节点后回溯,now传的是引用,1号主席树上从[1,1e9]查询5的路径上的节点自底向上地就有值了,值是1号主席树叶节点5的编号(在整个N*100的主席树结点中的唯一的编号)
//Q:所以又引出个问题 主席树开多大?
//A: 天呐这个问题我暂时无法回答。。。但我知道为什么开N*40*2=N*80会RE了,因为r1树的set操作,如果id串不存在的话,会涉及两次修改,也就是每次询问最多有两次修改,r1主席树应该开2*qlogx,r2主席树正常开qlogx,一共是3qlogx,所以你开3*40*N妥妥够...
}

int query(int l,int r,int now,int ql,int qr){
//对于r1树 ql=1,qr=p-1 查比p优先值小(优先值越小 优先级越高)的字符串的个数 ans累加只在这里用到
//对于r2树 ql=qr=id 单点查询 查id串的优先级
    if(ql>qr) return 0;//这句只为p==1的特殊情况
    if(ql<=l&&r<=qr) return hjt[now].sum;
    int m=l+r>>1;
    int ans=0;
    if(ql<=m) ans+=query(l,m,hjt[now].l,ql,qr);
    if(qr>m) ans+=query(m+1,r,hjt[now].r,ql,qr);
    return ans;
}

inline int getid(string s){
    if(mp[s]) return mp[s];
    return mp[s] = ++top ;
}

int main(){
    int q;
    scanf("%d",&q);
    string s;
    int x,id,p;
    for(int i=1;i<=q;++i){
        r1[i]=r1[i-1],r2[i]=r2[i-1];
        //Q:为什么后面update操作pre和now版本可以都写成r1[i]呢? A:因为你在这里复制过旧版了呀 你写r1[i-1],r1[i]也是可以的(除了要修改两次的r1树 set 先-1再+1 修改两次)(然后在update里r1[i]会被赋予新的节点编号)
        cin>>s;
        //每次先到r2树上查id字符串的优先级 再做修改
        //优先级x的范围是[1,1e9] 所以查询区间是[1,INF]
        if(s[0]=='s'){
            cin>>s>>x;
            id=getid(s);
            p=query(1,INF,r2[i],id,id);//到r2树上查询id的优先级 得到它优先级是p 为什么区间是[1,INF]呢?这关区间什么事呢?//其实区间应该是[1,max(id)],
            if(p) update(1,INF,r1[i],r1[i],p,-1);//r1[i]这棵树 的 p优先级的个数 -1 (因为p变成x了!)
            update(1,INF,r1[i],r1[i],x,1);//r1树 x优先级的数量 +1 //这里注意!!! 只有这里!只有这里不能写成update(1,INF,r1[i-1],r1[i], (其他update都可以!),因为r1有可能在if里面减过1,有了个新版本,新版本编号传回给r1[i]了,再修改必须在r1[i]上修改,这才是正确的pre版本编号
            update(1,INF,r2[i],r2[i],id,x-p);//r2树 id串的优先级 变为x(本来是p 加上x-p)
        }else if(s[0]=='q'){
            cin>>s;
            id=getid(s);
            p=query(1,INF,r2[i],id,id);
            if(p==0) puts("-1");
            else printf("%d\n",query(1,INF,r1[i],1,p-1));//r1树 查优先级是[1,p-1]的 有多少 求和
        }else if (s[0]=='u'){//Q:那undo不是会独占一天的版本?题目不是说 not including the day of this operation (undo) A:是的啊,undo就是有一个新版本,题目意思是,它撤销的的前d天,这个d不包括今天!d days(not including the day(重点:d days not include the day!) of this operation)
            cin>>x;
            r1[i]=r1[i-1-x];//第i天 撤销此前x天的操作 回到第i-1-x天的版本
            r2[i]=r2[i-1-x];
        }else{
            cin>>s;
            id=getid(s);
            p=query(1,INF,r2[i],id,id);//Q:r2[i]这个版本有了吗? A:有啊 循环最初不就复制了一份旧版嘛
            if(!p) continue;
            update(1,INF,r1[i],r1[i],p,-1);//p优先级的数量 -1
            update(1,INF,r2[i],r2[i],id,-p);//id串的优先级 -p 变为0
        }
    }
}
//天呐我学习的方式是自问自答!......

PS:两棵主席树空间开N*80 RE了,N*100才过。

我希望我写的东西,是被沙子掩埋的明珠~ 我会耐心地把沙子一点点拂去~

1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md或论文文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。 5、资源来自互联网采集,如有侵权,私聊博主删除。 6、可私信博主看论文后选择购买源代码。 1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md或论文文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。 5、资源来自互联网采集,如有侵权,私聊博主删除。 6、可私信博主看论文后选择购买源代码。 1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md或论文文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。 5、资源来自互联网采集,如有侵权,私聊博主删除。 6、可私信博主看论文后选择购买源代码。
应用背景为变电站电力巡检,基于YOLO v4算法模型对常见电力巡检目标进行检测,并充分利用Ascend310提供的DVPP等硬件支持能力来完成流媒体的传输、处理等任务,并对系统性能做出一定的优化。.zip深度学习是机器学习的一个子领域,它基于人工神经网络的研究,特别是利用多层次的神经网络来进行学习和模式识别。深度学习模型能够学习数据的高层次特征,这些特征对于图像和语音识别、自然语言处理、医学图像分析等应用至关重要。以下是深度学习的一些关键概念和组成部分: 1. **神经网络(Neural Networks)**:深度学习的基础是人工神经网络,它是由多个层组成的网络结构,包括输入层、隐藏层和输出层。每个层由多个神经元组成,神经元之间通过权重连接。 2. **前馈神经网络(Feedforward Neural Networks)**:这是最常见的神经网络类型,信息从输入层流向隐藏层,最终到达输出层。 3. **卷积神经网络(Convolutional Neural Networks, CNNs)**:这种网络特别适合处理具有网格结构的数据,如图像。它们使用卷积层来提取图像的特征。 4. **循环神经网络(Recurrent Neural Networks, RNNs)**:这种网络能够处理序列数据,如时间序列或自然语言,因为它们具有记忆功能,能够捕捉数据中的时间依赖性。 5. **长短期记忆网络(Long Short-Term Memory, LSTM)**:LSTM 是一种特殊的 RNN,它能够学习长期依赖关系,非常适合复杂的序列预测任务。 6. **生成对抗网络(Generative Adversarial Networks, GANs)**:由两个网络组成,一个生成器和一个判别器,它们相互竞争,生成器生成数据,判别器评估数据的真实性。 7. **深度学习框架**:如 TensorFlow、Keras、PyTorch 等,这些框架提供了构建、训练和部署深度学习模型的工具和库。 8. **激活函数(Activation Functions)**:如 ReLU、Sigmoid、Tanh 等,它们在神经网络中用于添加非线性,使得网络能够学习复杂的函数。 9. **损失函数(Loss Functions)**:用于评估模型的预测与真实值之间的差异,常见的损失函数包括均方误差(MSE)、交叉熵(Cross-Entropy)等。 10. **优化算法(Optimization Algorithms)**:如梯度下降(Gradient Descent)、随机梯度下降(SGD)、Adam 等,用于更新网络权重,以最小化损失函数。 11. **正则化(Regularization)**:技术如 Dropout、L1/L2 正则化等,用于防止模型过拟合。 12. **迁移学习(Transfer Learning)**:利用在一个任务上训练好的模型来提高另一个相关任务的性能。 深度学习在许多领域都取得了显著的成就,但它也面临着一些挑战,如对大量数据的依赖、模型的解释性差、计算资源消耗大等。研究人员正在不断探索新的方法来解决这些问题。
深度学习是机器学习的一个子领域,它基于人工神经网络的研究,特别是利用多层次的神经网络来进行学习和模式识别。深度学习模型能够学习数据的高层次特征,这些特征对于图像和语音识别、自然语言处理、医学图像分析等应用至关重要。以下是深度学习的一些关键概念和组成部分: 1. **神经网络(Neural Networks)**:深度学习的基础是人工神经网络,它是由多个层组成的网络结构,包括输入层、隐藏层和输出层。每个层由多个神经元组成,神经元之间通过权重连接。 2. **前馈神经网络(Feedforward Neural Networks)**:这是最常见的神经网络类型,信息从输入层流向隐藏层,最终到达输出层。 3. **卷积神经网络(Convolutional Neural Networks, CNNs)**:这种网络特别适合处理具有网格结构的数据,如图像。它们使用卷积层来提取图像的特征。 4. **循环神经网络(Recurrent Neural Networks, RNNs)**:这种网络能够处理序列数据,如时间序列或自然语言,因为它们具有记忆功能,能够捕捉数据中的时间依赖性。 5. **长短期记忆网络(Long Short-Term Memory, LSTM)**:LSTM 是一种特殊的 RNN,它能够学习长期依赖关系,非常适合复杂的序列预测任务。 6. **生成对抗网络(Generative Adversarial Networks, GANs)**:由两个网络组成,一个生成器和一个判别器,它们相互竞争,生成器生成数据,判别器评估数据的真实性。 7. **深度学习框架**:如 TensorFlow、Keras、PyTorch 等,这些框架提供了构建、训练和部署深度学习模型的工具和库。 8. **激活函数(Activation Functions)**:如 ReLU、Sigmoid、Tanh 等,它们在神经网络中用于添加非线性,使得网络能够学习复杂的函数。 9. **损失函数(Loss Functions)**:用于评估模型的预测与真实值之间的差异,常见的损失函数包括均方误差(MSE)、交叉熵(Cross-Entropy)等。 10. **优化算法(Optimization Algorithms)**:如梯度下降(Gradient Descent)、随机梯度下降(SGD)、Adam 等,用于更新网络权重,以最小化损失函数。 11. **正则化(Regularization)**:技术如 Dropout、L1/L2 正则化等,用于防止模型过拟合。 12. **迁移学习(Transfer Learning)**:利用在一个任务上训练好的模型来提高另一个相关任务的性能。 深度学习在许多领域都取得了显著的成就,但它也面临着一些挑战,如对大量数据的依赖、模型的解释性差、计算资源消耗大等。研究人员正在不断探索新的方法来解决这些问题。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值