loj 数列分块入门 6 9(区间众数)_ahu12345678的博客-程序员宅基地

技术标签: 数据结构与算法  

6

题意

给出一个长为\(n\)的数列,以及\(n\)个操作,操作涉及单点插入,单点询问,数据随机生成。

题解

参考:http://hzwer.com/8053.html

每个块内用一个\(vector\)维护,每次插入时先找到位置所在的块,再暴力插入。

如果数据不随机,即如果先在一个块有大量单点插入,这个块的大小会大大超过\(\sqrt n\),那块内的暴力就没有复杂度保证了。

为此引入一个操作:重新分块(重构)

\(\sqrt n\)次插入后,重新把数列平均分一下块,重构需要的复杂度为\(O(n)\),重构的次数为\(\sqrt n\),所以重构的复杂度没有问题,而且保证了每个块的大小相对均衡。

当然,也可以当某个块过大时重构,或者只把这个块分成两半。

// 代码中采取的是当块过大时进行重构。

Code

#include <bits/stdc++.h>
#define maxn 200010
#define C 20
#define F(i, a, b) for (int i = (a); i < (b); ++i)
#define F2(i, a, b) for (int i = (a); i <= (b); ++i)
#define dF(i, a, b) for (int i = (a); i > (b); --i)
#define dF2(i, a, b) for (int i = (a); i >= (b); --i)
using namespace std;
typedef long long LL;
int n, blo, a[maxn], num;
vector<int> v[510];
struct node { int bl, p; };
node query(int p) {
    int i=0;
    while (p>v[i].size()) p -= v[i++].size();
    return {i, p-1};
}
void rebuild() {
    int cnt=0;
    F(i, 0, num) {
        for (auto x : v[i]) a[cnt++] = x;
        v[i].clear();
    }
    blo = sqrt(cnt); num = (cnt+blo-1)/blo;
    F(i, 0, cnt) v[i/blo].push_back(a[i]);
}
void insert(int p, int x) {
    node nd = query(p);
    v[nd.bl].insert(v[nd.bl].begin()+nd.p, x);
    if (v[nd.bl].size()>C*blo) rebuild();
}
int main() {
    scanf("%d", &n); blo = sqrt(n);
    F(i, 0, n) {
        scanf("%d", &a[i]);
        v[i/blo].push_back(a[i]);
    }
    num = (n+blo-1)/blo;
    F(i, 0, n) {
        int op, l, r, c;
        scanf("%d%d%d%d", &op, &l, &r, &c);
        if (op) {
            node nd = query(r);
            printf("%d\n", v[nd.bl][nd.p]);
        }
        else insert(l, r);
    }
    return 0;
}

9

题意

给出一个长为\(n\)的数列,以及\(n\)个操作,操作涉及询问区间的最小众数。

题解

参考:http://hzwer.com/3582.html

  1. 离散化

  2. 对每一个数开一个,即对每个数用一个\(vector\)按序记录它所有的出现位置。

  3. 预处理\(f[s][t]\)表示第\(s\)块到第\(t\)块的最小众数:
    方法是:枚举\(s\),向右扫,每扫一个块得到一个值。
    复杂度:\(\sqrt n*\sqrt n+(\sqrt n-1)*\sqrt n+\cdots+2*\sqrt n+\sqrt n=\sqrt n*(1+2+\cdots+\sqrt n)=O(n\sqrt n)\)

  4. 对于一个询问\([l,r]\)
    不完整的块中共有\(2\sqrt n\)个数,完整的块根据3. 中的预处理得到一个数。
    暴力比较这\(2\sqrt n+1\)个数的出现次数,
    方法是:要知道\(x\)\([l,r]\)中的出现次数,只需在\(vector[x]\)中进行二分查找。
    复杂度:\(O(\sqrt n*logn)\)

Code

#include <bits/stdc++.h>
#define F(i, a, b) for (int i = (a); i < (b); ++i)
#define F2(i, a, b) for (int i = (a); i <= (b); ++i)
#define dF(i, a, b) for (int i = (a); i > (b); --i)
#define dF2(i, a, b) for (int i = (a); i >= (b); --i)
#define maxn 100010
#define inf 0x3f3f3f3f
using namespace std;
int cnt[maxn], a[maxn], n, num, blo, f[1010][1010], bl[maxn], mp2[maxn];
map<int, int> mp;
vector<int> v[maxn];
typedef long long LL;
inline void update(int temp, int& maxx, int x, int& ans) {
    if (temp>maxx || (temp==maxx&&mp2[x]<mp2[ans])) {
        maxx = temp, ans = x;
    }
}
void pre(int s) {
    memset(cnt, 0, sizeof cnt);
    int ans = -inf, maxx = 0;
    F(i, s, num) {
        F(j, i*blo, min((i+1)*blo, n)) {
            ++cnt[a[j]];
            update(cnt[a[j]], maxx, a[j], ans);
        }
        f[s][i] = ans;
    }
}
inline int count(int l, int r, int x) {
    return upper_bound(v[x].begin(), v[x].end(), r)-upper_bound(v[x].begin(), v[x].end(), l-1);
}

int query(int l, int r) {
    int ans = -inf, maxx = 0;
    F(i, l, min(r+1, (bl[l]+1)*blo)) {
        int temp = count(l, r, a[i]);
        update(temp, maxx, a[i], ans);
    }
    if (bl[l]!=bl[r]) {
        F2(i, bl[r]*blo, r) {
            int temp = count(l, r, a[i]);
            update(temp, maxx, a[i], ans);
        }
    }
    if (bl[l]+1<=bl[r]-1) {
        int x = f[bl[l]+1][bl[r]-1];
        int temp = count(l, r, x);
        update(temp, maxx, x, ans);
    }
    return ans;
}
int main() {
    scanf("%d", &n); blo = sqrt(n);
    int tot=0;
    F(i, 0, n) {
        scanf("%d", &a[i]);
        if (!mp[a[i]]) {
            mp[a[i]] = ++tot;
            mp2[tot] = a[i];
        }
        bl[i] = i/blo;
        v[a[i]=mp[a[i]]].push_back(i);
    }
    num = bl[n-1]+1;
    F(i, 0, num) pre(i);
    F(i, 0, n) {
        int l, r;
        scanf("%d%d", &l, &r); --l, --r;
        printf("%d\n", mp2[query(l, r)]);
    }
    return 0;
}

转载于:https://www.cnblogs.com/kkkkahlua/p/8479216.html

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/ahu12345678/article/details/101911298

智能推荐

PAT 乙级 1031 查验身份证_l_d_x的博客-程序员宅基地

一个合法的身份证号码由17位地区、日期编号和顺序编号加1位校验码组成。校验码的计算规则如下:首先对前17位数字加权求和,权重分配为:{7,9,10,5,8,4,2,1,6,3,7,9,10,5,8,4,2};然后将计算的和对11取模得到值Z;最后按照以下关系对应Z值与校验码M的值:Z:0 1 2 3 4 5 6 7 8 9 10M:1 0 X 9 8 7 6 5 4 3 2现在给定一些身份证号码,请你验证校验码的有效性,并输出有问题的号码。输入格式:输入第一行给出正整数N(≤100)

【技术探讨】无线通信模块拉距测试,是否一定要带笔记本电脑?_拉距测试 注意事项_微网高通-dingyg的博客-程序员宅基地

用户购买无线模块后,一般第一步就是进行拉距测试,通常是准备2个笔记本电脑,一部电脑是放在在办公室有人值守,另外一部电脑在外场,双方使用手机或微信进行实时沟通测试结果,对于Sub-G的无线模块通常通信距离较远可以达到公里级甚至数公里之远,而笔记本的续航时间通常是2-3个小时,很多用户测试到一半,不得不提前终止测试,回去给笔记本电脑充电,次日再来。 而由于无线通信的距离是一个渐变的、模拟的数据,用户需要在临界区域反复的来回测试,才能比较准确的找到无线模块的稳定通信距离,这对笔记本电脑的续航时间带来了进..._拉距测试 注意事项

MySQL连接数超过限制的解决方法-程序员宅基地

最近网站出现 User 数据库名称 has already more than 'max_user_connections' active connections 的报错,网站瘫痪。有必要研究下这个问题。max_user_connections 是 MySQL 用户连接数的最大值设置,整段语句的意思是:服务器的 MySQL 的最大连接数参数设置不足。解决方法:修改 MySQL 安装目录

IT行业相关职位资质大剖析-程序员宅基地

软件开发工程师  1、国家正规院校本科以上学历;  2、计算机及相关理工类专业;  3、熟练net/Java/J2EE/Powerbulider/SAP/Oracle等技术或者对其一有很深造诣;  4、善于沟通及团队合作;  5、具备良好分析、解决问题能力;  6、有相关的软件开发经验优先录用。  资深硬件工程师(电子产品)   1、计算机硬件、电子工程、自动化等相关专业;本科以上学历;有嵌入式电..._开发工程师专业资质怎么填

java读取对象失败_Java:使用文件中的ObjectInputStream读取队列对象给出nullPointerException...-程序员宅基地

class QStorage{Queue q = new PriorityQueue(5);public Queue readQ(){try{FileInputStream fin = new FileInputStream("/home/requestQ.ser");ObjectInputStream ois = new ObjectInputStream(fin);q = (Queue)ois..._objectinputstream读取多个对象为null

2021年4月11日度小满笔试_度小满开发笔试题_zzxhqzz的博客-程序员宅基地

度小满笔试第一题题目描述:小A在宾馆打工。一日,小A需要把宾馆一个走廊上n个灯全部关掉。走廊上的灯编号为1—n。宾馆的电路有设计缺陷。宾馆的走廊上有n个开关,第i个开关只可以改变i~n号电灯的状态,即亮的熄灭,熄灭的变亮。 小A一秒按一次开关,一共按了m次。给出小A每次按下的开关编号,请问每一盏灯第一次关掉的时间。一开始,所有灯都是亮着的。输入描述输入第一行包含两个数,n,m 接下来一行m个数,代表小A每次按下的开关编号输出描述输出一行n个数,代表每盏电灯最后关掉的时间。样例输入4 22 _度小满开发笔试题

随便推点

linux查看用户密码(linux查看用户密码命令)_普通网友的博客-程序员宅基地

1、用户名和密码的存储位置存储帐号的文件:/etc/passwd存储密码的文件:/etc/shadow2、可以使用cat、more、head、tail以及vim等命令查看或者修改,如下图所示:比如要查找系统中admin普通用户的密码,则执行:cat/etc/shadow|grep"admin"3、注意:/etc/shadow文件中的密码不是明文密码.如上图所示,第1个“:”号后面的即为“口令”字段,存放的是加密后的用户口令字,长度为13个字符.如果为空,则对应用户没有口令,登录时不需要口令;_linux查看用户密码

小程序cover-view无法盖住canvas 层级太高_view如何覆盖再canvas上_风靓的博客-程序员宅基地

<ec-canvasforce-use-old-canvas="{{true}}"style="width:100%;height:400rpx;"id="mychart-one"canvas-id="mychart-pie"ec="{{ecMap}}"></ec-canvas>设置force-use-old-canvas="{{true}}"_view如何覆盖再canvas上

C 可变参数的使用_第二个形参表比第一个长-程序员宅基地

C 可变参数的使用C中的可变参数需要使用 stdarg.h 头文件。此头文件中声明了一个类型va_list和三个函数——va_start、va_arg 和 va_end。让我们先看一个求均值函数的实现,看看C中可变参数是如何使用的。样例代码#include #include #include float average(int count_第二个形参表比第一个长

Android中获取TextView行数-程序员宅基地

项目中发现,如果直接通过TextView.getLineCount()方法获取行数时,总是0,研究发现,setText()后立即调用getLineCount(),这时TextView还未完成measure,要想正确的获取TextView的行数有两种方法1.用ViewTreeObserver监听View初始化的各种状态使用ViewTreeObserver的OnPreDrawListene..._android 获取textview行数

历届奥斯卡获奖电影-程序员宅基地

  第1届奥斯卡(1927-1928年度)   最佳影片:翼 Wings   第2届奥斯卡(1928-1929年度)   最佳影片:百老汇的旋律/红伶秘史 The Broadway Melody   第3届奥斯卡(1929-1930年度)   最佳影片:西线无战事 All Quiet on the Western Front   第4届奥斯卡(1930-1931年度)   最佳影片:壮志千

IOS 自动化测试安装以及部署-程序员宅基地

朋友让我帮忙制作一个可以自动划动手机的东西,手边只有Iphone于是研究了IOS自动化相关的东西。

推荐文章

热门文章

相关标签