P5356 [Ynoi2017] 由乃打扑克

我手把手教她打扑克 qwq

综合分析一下2个操作,查找区间第k小的值,感觉可以用主席树,区间修改那没事了

考虑分块做法,块长B

分析第一个操作

只需要维护数列的单调性,然后二分答案上二分就ok了

分析第二个操作

维护一个加法懒标记即可

口胡了一下感觉很简单

仔细分析一下第一个操作

二分找到一个“第k小值”,再进行check,check的过程中散块遍历一遍,整块二分找到最后一个小于等于x的(只有前面部分有贡献),分析一下时间复杂度,预处理 O(\frac{n}{B}*BlogB),(分块完排序),二分答案O(\frac{n}{B}*lognlogV),二分O(\frac{n}{B}*BlogB)

第二个操作

散块可以暴力然后重构,整块上懒标记,时间复杂度O(\frac{n}{B}*B*logB)

总时间复杂度O(m*\frac{n}{B}*lognlogV)    maybe..

应该需要优化?

分析一下二分答案这块,我们不一定要把L定义无穷小,R定义无穷大,可以维护一下区间最大值区间最小值这样可以转化为O(\frac{n}{B}*logn)差不多能卡过去了,我是这样干的,二分剪枝一下

分析一下散块区间加,不一定要O(BlogB)的排序,我们可以把数列分成2块,没有加的和加的,两边其实都是有序的,因此可以用归并排序优化成O(B)

快长最优可能是sqrt(n)logn..

小优化

1.不一定要把散块重构,如果没有询问到,可以不做,我们用线段树区间赋值的思想,修改后标记一下这个块需要重构,等询问的时候问到了再进行重构

void work(int l,int r){
    int p=pos[l];
    int q=pos[r];
    for(int i=p;i<=q;i++){
        if(re[i]){
            rebuild(i);
            re[i]=0;
        }
    }
}

2.二分答案优化

    if(k<1 || R-L+1<k){
            return -1;
    }

3.块内二分优化

    if(v[id].front()+add[id]>x){//没有比x小的
        return 0;
    }
    if(v[id].back()+add[id]<=x){//都是小于等于x的
        return r+1;//r-0+1;
    }

4.维护区间最大值最小值优化

    for(int i=p+1;i<=q-1;i++){//最后一个是最大
        res=max(res,v[i].back()+add[i]);
    }
    for(int i=p+1;i<=q-1;i++){//第一个是最小
        res=min(res,v[i].front()+add[i]);
    }

完整代码

#include<iostream>
#include<cmath>
#include<algorithm>
#include<bitset>
#include<cstring>
#include<vector>
#define INF (1ll<<60)
using namespace std;
typedef long long ll;
const int N=1e5+9;
const int B=1e4+9;
namespace Lan {
    inline string sread() {
        string s=" ";char e=getchar();
        while(e==' '||e=='\n')e=getchar();
        while(e!=' '&&e!='\n')s+=e,e=getchar();
        return s;
    }
    inline void swrite(string s){
        for(char e:s)putchar(e);
        printf("\n");
    }
    inline ll read() {
        ll x=0,y=1;char c=getchar();
        while(!isdigit(c)){if(c=='-')y=-1;c=getchar();}
        while(isdigit(c)){x=(x<<3)+(x<<1)+(c^48);c=getchar();}
        return x*=y;
    }
    inline void write(ll x) {
        if(x<0){x=-x,putchar('-');}ll sta[35],top=0;
        do sta[top++]=x%10,x/=10;while(x);
        while(top)putchar(sta[--top]+'0');
    }
}using namespace Lan;
ll a[N];
int L[B],R[B],pos[N];
ll add[B];
int re[B];
vector<ll> v[B];
inline void rebuild(int id){
    v[id].clear();
    for(int i=L[id];i<=R[id];i++){
        v[id].push_back(a[i]);
    }
    sort(v[id].begin(),v[id].end());
}
inline int binary(int id,int x){
    int l=0,r=v[id].size()-1;
    if(v[id].front()+add[id]>x){//没有比x小的
        return 0;
    }
    if(v[id].back()+add[id]<=x){//都是小于等于x的
        return r+1;//r-0+1;
    }
    int res=0;
    while(l<=r){
        int mid=(l+r)>>1;
        if(v[id][mid]+add[id]<=x){//小于等于x,选大一点
            l=mid+1;
            res=mid+1;//小于等于x的有贡献
        }else{
            r=mid-1;
        }
    }
    return res;
}
inline ll getmax(int l,int r){
    ll res=-INF;
    int p=pos[l];
    int q=pos[r];
    if(p==q){
        for(int i=l;i<=r;i++){
            res=max(res,a[i]+add[pos[i]]);
        }
    }else{
        for(int i=l;i<=R[p];i++){
            res=max(res,a[i]+add[pos[i]]);
        }
        for(int i=L[q];i<=r;i++){
            res=max(res,a[i]+add[pos[i]]);
        }
        for(int i=p+1;i<=q-1;i++){//最后一个是最大
            res=max(res,v[i].back()+add[i]);
        }
    }   
    return res;
}
inline ll getmin(int l,int r){
    ll res=INF;
    int p=pos[l];
    int q=pos[r];
    if(p==q){
        for(int i=l;i<=r;i++){
            res=min(res,a[i]+add[pos[i]]);
        }
    }else{
        for(int i=l;i<=R[p];i++){
            res=min(res,a[i]+add[pos[i]]);
        }
        for(int i=L[q];i<=r;i++){
            res=min(res,a[i]+add[pos[i]]);
        }
        for(int i=p+1;i<=q-1;i++){//第一个是最小
            res=min(res,v[i].front()+add[i]);
        }
    }
    return res;
}
inline int check(int l,int r,int x){
    int p=pos[l];
    int q=pos[r];
    int res=0;
    if(p==q){
        for(int i=l;i<=r;i++){
            if(a[i]+add[pos[i]]<=x){
                res++;
            }
        }
    }else{
        for(int i=l;i<=R[p];i++){
            if(a[i]+add[pos[i]]<=x){
                res++;
            }
        }
        for(int i=L[q];i<=r;i++){ 
            if(a[i]+add[pos[i]]<=x){
                res++;
            }
        }
        for(int i=p+1;i<=q-1;i++){
            res+=binary(i,x);
        }
    }
    return res;
}
void work(int l,int r){
    int p=pos[l];
    int q=pos[r];
    for(int i=p;i<=q;i++){
        if(re[i]){
            rebuild(i);
            re[i]=0;
        }
    }
}
inline int kth(int k,int L,int R){
    if(k<1 || R-L+1<k){
        return -1;
    }
    work(L,R);
    int res=-1;
    ll l=getmin(L,R),r=getmax(L,R);
    while(l<=r){
        ll mid=(l+r)>>1;
        if(check(L,R,mid)<k){//选的值太小
            l=mid+1;
        }else{
            r=mid-1;
            res=mid;
        }
    }
    return res;
}
inline void modify(int l,int r,int k){
    int p=pos[l];
    int q=pos[r];
    if(p==q){
        for(int i=l;i<=r;i++){
            a[i]+=k;
        }
        re[p]=1;
        // rebuild(p);
    }else{
        for(int i=l;i<=R[p];i++){
            a[i]+=k;
        }
        re[p]=1;
        // rebuild(p);
        for(int i=p+1;i<=q-1;i++){
            add[i]+=k;
        }
        for(int i=L[q];i<=r;i++){
            a[i]+=k;
        }
        re[q]=1;
        // rebuild(q);
    }
}
int main(){
    // ios::sync_with_stdio(false);
    // cin.tie(0),cout.tie(0);
    int n,m;
    n=read();
    m=read();
    for(int i=1;i<=n;i++){
        a[i]=read();
    }
    int blo=sqrt(n);
    int t=ceil(1.0*n/blo);
    for(int i=1;i<=t;i++){
        L[i]=(i-1)*blo+1;
        R[i]=(i==t?n:i*blo);
    }
    for(int i=1;i<=t;i++){
        for(int j=L[i];j<=R[i];j++){
            pos[j]=i;
        }
    }
    for(int i=1;i<=n;i++){
        v[pos[i]].push_back(a[i]);
    }
    for(int i=1;i<=t;i++){
        sort(v[i].begin(),v[i].end());
    }
    for(int i=1;i<=m;i++){
        int op,l,r,k;
        op=read();
        l=read();
        r=read();
        k=read();
        if(op==1){
            write(kth(k,l,r));
            putchar('\n');
        }else{
            modify(l,r,k);
        }
    }
    return 0;
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/530791.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

抖音电商发布2024春茶消费数据报告,90后00后占春茶消费数量四成

清明已过&#xff0c;茶香正浓。进入4月&#xff0c;各类春茗进入销售旺季。近日&#xff0c;抖音电商发布《2024春茶消费数据报告》&#xff08;以下简称“报告”&#xff09;&#xff0c;展示平台用户在原叶茶消费领域的最新趋势。 报告显示&#xff0c;在刚过去的3月&#…

dayjs 判断是否今天、本周内、本年内、本年外显示周几、月份等

效果: 判断是否今天需从 dayjs 中引入 isToday 插件&#xff1b; 判断是否两个日期之间需从 dayjs 中引入 isBetween 插件 import dayjs from dayjs import isToday from dayjs/plugin/isToday import isBetween from dayjs/plugin/isBetween// 注册插件 dayjs.extend(isBet…

论文学习D2UNet:用于地震图像超分辨率重建的双解码器U-Net

标题&#xff1a;&#xff1a;Dual Decoder U-Net for Seismic Image Super-Resolution Reconstruction ——D2UNet&#xff1a;用于地震图像超分辨率重建的双解码器U-Net 期刊&#xff1a;IEEE Transactions on Geoscience and Remote Sensing 摘要&#xff1a;从U-Net派生…

Python实现滑块验证码识别,最简单的一种,没有任何加密

网址链接&#xff1a;衣丰 & 2010-聚衣网(juyi5.cn) - 常熟市聚衣网&#xff0c;聚衣网女装&#xff0c;江苏省女装批发&#xff0c;苏州市女装批发&#xff0c;常熟市女装批发&#xff0c;网销女装一件代发&#xff0c;全国最低价 平时采集数据&#xff0c;频率过快&…

2024年租用阿里云服务器一年多少钱?免费版不要钱,收费版61元起

2024年阿里云服务器一年多少钱&#xff1f;如果是申请试用版云服务器就不需要钱&#xff0c;如果是购买收费版目前最低仅需61元&#xff0c;不同阶段&#xff0c;阿里云所推出的最低价格的云服务器不同&#xff0c;2024年4月份&#xff0c;阿里云服务器的活动价格在再次更新了&…

Ubuntu 20.04.06 PCL C++学习记录(二十一)【切记使用rm * -rf前先确认是否是对应文件夹】

[TOC]PCL中点云分割模块的学习 学习背景 参考书籍&#xff1a;《点云库PCL从入门到精通》以及官方代码PCL官方代码链接,&#xff0c;PCL版本为1.10.0&#xff0c;CMake版本为3.16&#xff0c;测试点云下载地址 学习内容 根据欧几里得距离和需要保持的用户可自定义条件对点进…

8. 托盘图标与菜单

内容概要&#xff1a; 托盘图标的设置与事件 右键菜单的相关操作 窗口组件&#xff1a; 1.组件的属性 组件属性&#xff1a;位置 组件属性&#xff1a;可视 2.组件的事件 窗口_托盘事件-带有参数的事件的使用方法 3.组件的方法 置托盘图标 菜单的操作 1.创建菜单 …

大话设计模式——20.解释器模式(Interpreter Pattern)

简介 给定一个语言&#xff0c;定义它的文法的一种表示&#xff0c;并定义一个解释器&#xff0c;这个解释器使用该表示来解释语言中的句子 UML图 应用场景 某种特定类型的问题发生的频率足够多&#xff0c;就可能值得将该问题的各个实例表述为一个简单语言中的句子&#xff0…

关于pandas 无法读取 csv 文件数据的解决方式

你好&#xff0c;我是 shengjk1&#xff0c;多年大厂经验&#xff0c;努力构建 通俗易懂的、好玩的编程语言教程。 欢迎关注&#xff01;你会有如下收益&#xff1a; 了解大厂经验拥有和大厂相匹配的技术等 希望看什么&#xff0c;评论或者私信告诉我&#xff01; 文章目录 …

词频统计程序

使用Hadoop MapReduce处理文本文件&#xff0c;Mapper负责将文本分割为单词&#xff0c;然后Reducer对每个单词进行计数&#xff0c;最后将结果写入输出文件。 // 定义WordCount公共类 public class WordCount {// 主入口方法&#xff0c;处理命令行参数public static void m…

C++实现幻方实验

我们这个实验目的是实现大于2的奇数的n阶幻方 根据上述的例子我们可以看到一些规律&#xff0c;显示1放在最上方中间的位置&#xff0c;然后向右上方延申&#xff0c;在达到n这个数字时&#xff0c;停止延申&#xff0c;然后在n的下方开始n1的新一轮延申。明白了原理之后就很容…

羊大师说:“羊奶”,每一滴都值得珍惜

亲爱的读者们&#xff0c;我是羊大师。在无数次探索自然的奥秘和追求健康生活的旅途中&#xff0c;我发现了一种珍贵的液体——羊奶。今天&#xff0c;我要带大家深入了解羊奶&#xff0c;看看它是如何成为餐桌上的超级食品。 1. 羊奶的营养价值 首先&#xff0c;羊奶含有丰富…

财富池指标公式--实用多空博弈买点提示通达信副图指标公式源码

实用多空博弈买点提示通达信副图指标&#xff0c;不含未来函数&#xff0c;信号简单。 当白色多头能量线金叉黄色空方能量线&#xff0c;且出现紫色向上的信号后参考买入是一个较为稳健的买点&#xff0c;也可在白色多头能量线金叉黄色空方能量线时就介入。 配合其它选股指标…

向新而行,企商在线做好“AI+”大文章

文&#xff1a;中国高新技术产业导报 记者 张伟 作为人工智能典型服务商屡获认可&#xff0c;入选第二批北京市通用人工智能产业创新伙伴计划成员&#xff1b;作为唯一上榜的AI算力企业&#xff0c;实力入选中国信通院《2023高质量数字化转型产品及服务全景图&#xff08;9月…

ubuntu20挂载webdav

WebDAV 是个好东西&#xff0c;尤其是配个自己的 NAS 使用&#xff0c;熟悉以后就再也离不开它啦 sudo apt-get update sudo apt-get install davfs2 上下左右键可以切换到“是”选项 2.创建目录挂载点 sudo mkdir /mnt/webdav 3.配置 davfs2 编辑 davfs2.conf 文件以配置 da…

系统监测工具-tcpdump的使用

一个简单的tcpdump抓包过程。主要抓包观察三次握手&#xff0c;四次挥手的数据包 有两个程序&#xff1a;客户端和服务器两个程序 服务器端的ip地址使用的是回环地址127.0.0.1 端口号使用的是6000 tcpdump -i 指定用哪个网卡等&#xff0c;dstip地址端口指定抓取目的地址…

Linux:gcc

Linux&#xff1a;gcc gcc概述语言发展史gcc的编译过程预处理编译汇编 gcc的链接过程动态库与静态库 gcc概述 GCC&#xff08;英文全拼&#xff1a;GNU Compiler Collection&#xff09;是 GNU 工具链的主要组成部分&#xff0c;是一套以 GPL 和 LGPL 许可证发布的程序语言编译…

自定义类型—结构体

目录 1 . 结构体类型的声明 1.1 结构的声明 1.2 结构体变量的创建与初始化 1.3 结构体的特殊声明 1.4 结构体的自引用 2. 结构体内存对齐 2.1 对齐规则 2.2 为什么存在内存对齐 2.3 修改默认对齐数 3. 结构体传参 4.结构体实现位段 4.1 位段的内存分配 1 . 结构体类…

12.C++常用的算法_遍历算法

文章目录 遍历算法1. for_each()代码工程运行结果 2. transform()代码工程运行结果 3. find()代码工程运行结果 遍历算法 1. for_each() 有两种方式&#xff1a; 1.普通函数 2.仿函数 代码工程 #define _CRT_SECURE_NO_WARNINGS #include<iostream> #include<vect…

数据结构之树的性质总结

节点的度&#xff1a;该节点拥有的孩子个数 叶子节点&#xff1a;度为0的节点 层数&#xff1a;根节点为第一层&#xff0c;根的子节点为第二层&#xff0c;以此类推 所有树的性质&#xff1a;所有节点的总度数等于节点数减一 完全m叉树性质 完全m 叉树&#xff0c;节点的…