给你一个长度为\(n\)序列\(A\),有\(m\)个操作,操作分为两种:

  • 输入\(x,y,c\),表示对\(i\in[x,y]\),令\(A_{i}=min(A_{i},c)\)
  • 输入\(x,y,k\),表示询问区间 \([x,y]\) 中的第\(k\)小数

Solution

考虑分块,块内排序,同时记录这一块被整体取过的 \(min\) 的最小值

对于修改,对不完整的块,我们直接暴力在原序列上修改然后重建块,标记不动

对完整的块,只修改标记

这样修改的时间复杂度为 \(O(k \log k)\),其中 \(k\) 为块大小

对于询问,我们二分答案,考虑检验,在每个完整的块上统计需要检查标记,如果标记比当前枚举的值小则直接计数,否则在块上再次二分;对于不完整的块,检查标记并在序列上暴力查询即可。查询时间复杂度的宽界为 \(O(\frac{n}{k} \log k \log V)\)

求解根号平衡,\(k = \frac{n}{k} \log V\),得 \(k = \sqrt{n \log V}\),考虑到 \(V \leq 10^9\),取 \(k=\sqrt{30n}\) ,实际上由于常数问题,\(k\)取 \(\sqrt{3n}\) 即可

#include <bits/stdc++.h>
using namespace std; const int N = 1005;
const int inf = 1e+9+7;
vector <int> b[N];
int n, m, a[N*N], bel[N*N], bl[N], br[N], tag[N], K, tot; void build() {
K = sqrt(3*n);
for(int i=1;i<=n;i++) bel[i] = i/K+1;
for(int i=1;i<=n;i++) br[bel[i]]=i;
for(int i=n;i>=1;i--) bl[bel[i]]=i;
for(int i=1;i<=n;i++) b[bel[i]].push_back(a[i]);
for(int i=1;i<=n;i++) tot = max(tot,bel[i]);
for(int i=1;i<=tot;i++) tag[i] = inf;
for(int i=1;i<=tot;i++) sort(b[i].begin(), b[i].end());
} void modify_part(int l,int r,int x) {
int id = bel[l];
for(int i=l;i<=r;i++) a[i] = min(a[i],x);
b[id].clear();
for(int i=bl[id];i<=br[id];i++) b[id].push_back(a[i]);
sort(b[id].begin(), b[id].end());
} void modify(int l,int r,int x) {
for(int i=bel[l]+1;i<bel[r];i++) tag[i] = min(tag[i],x);
if(bel[l] == bel[r]) { // !!
modify_part(l, r, x);
}
else {
modify_part(l, br[bel[l]], x);
modify_part(bl[bel[r]], r, x);
}
} int check_part(int l,int r,int x) {
if(tag[bel[l]]<=x) return r-l+1;
int ans = 0;
for(int i=l;i<=r;i++) ans += a[i]<=x?1:0;
return ans;
} int check_block(int i,int x) {
if(tag[i]<=x) return br[i]-bl[i]+1;
return upper_bound(b[i].begin(),b[i].end(),x) - b[i].begin();
} int check(int l,int r,int x) {
int ans = 0;
for(int i=bel[l]+1;i<bel[r];i++) ans += check_block(i,x);
if(bel[l]==bel[r]) { // !!
ans = check_part(l, r, x);
}
else {
ans += check_part(l, br[bel[l]], x);
ans += check_part(bl[bel[r]], r, x);
}
return ans;
} int query(int ql,int qr,int k) {
int l=1, r=1e9+1;
while(l<r) {
int mid = (l+r)/2;
if(check(ql,qr,mid) < k) l=mid+1;
else r=mid;
}
return l;
} int main() {
ios::sync_with_stdio(false);
cin>>n>>m;
for(int i=1;i<=n;i++) cin>>a[i];
build();
for(int i=1;i<=m;i++) {
int t1,t2,t3,t4;
cin>>t1>>t2>>t3>>t4;
if(t1==1) {
modify(t2,t3,t4);
}
if(t1==2) {
cout<<query(t2,t3,t4)<<endl;
}
}
}

Wannafly Camp 2020 Day 1I K小数查询 - 分块的更多相关文章

  1. 2020 CCPC Wannafly Winter Camp Day1 - I. K小数查询(分块)

    题目链接:K小数查询 题意:给你一个长度为$n$序列$A$,有$m$个操作,操作分为两种: 输入$x,y,c$,表示对$i\in[x,y] $,令$A_{i}=min(A_{i},c)$ 输入$x,y ...

  2. Wannafly Winter Camp 2020 Day 6J K重排列 - dp

    求 \(K\) 是多少个 \(n\) 元置换的周期.\(T\leq 100, n\leq 50, K \leq 10^{18}\) Solution 置换可以被试做若干个环组成的有向图,于是考虑 dp ...

  3. Wannafly Camp 2020 Day 3I N门问题 - 概率论,扩展中国剩余定理

    有一个猜奖者和一个主持人,一共有 \(n\) 扇门,只有一扇门后面有奖,主持人事先知道哪扇门后有奖,而猜奖者不知道.每一轮,猜奖者选择它认为的有奖概率最大(如果有多个最大,随机选一个)的一扇门,主持人 ...

  4. Wannafly Camp 2020 Day 3F 社团管理 - 决策单调性dp,整体二分

    有 \(n\) 个数构成的序列 \({a_i}\),要将它划分为 \(k\) 段,定义每一段的权值为这段中 \((i,j) \ s.t. \ i<j,\ a_i=a_j\) 的个数,求一种划分方 ...

  5. Wannafly Camp 2020 Day 2B 萨博的方程式 - 数位dp

    给定 \(n\) 个数 \(m_i\),求 \((x_1,x_2,...,x_n)\) 的个数,使得 \(x_1 \ xor\ x_2\ xor\ ...\ xor\ x_n = k\),且 \(0 ...

  6. Wannafly Camp 2020 Day 1D 生成树 - 矩阵树定理,高斯消元

    给出两幅 \(n(\leq 400)\) 个点的无向图 \(G_1 ,G_2\),对于 \(G_1\) 的每一颗生成树,它的权值定义为有多少条边在 \(G_2\) 中出现.求 \(G_1\) 所有生成 ...

  7. Wannafly Camp 2020 Day 2I 堡堡的宝藏 - 费用流

    感谢这道题告诉我KM求的是 完备 最大权匹配 :( #include <bits/stdc++.h> using namespace std; #define reset(x) memse ...

  8. Wannafly Camp 2020 Day 1C 染色图 - 组合数学,整除分块

    定义一张无向图 G=⟨V,E⟩ 是 k 可染色的当且仅当存在函数 f:V↦{1,2,⋯,k} 满足对于 G 中的任何一条边 (u,v),都有 f(u)≠f(v). 定义函数 g(n,k) 的值为所有包 ...

  9. Wannafly Camp 2020 Day 6M 自闭 - 模拟

    按题意模拟,又乱又烦,没什么可说的 #include <bits/stdc++.h> using namespace std; #define int long long int n,m, ...

随机推荐

  1. Shiro -- (一)简介

    简介: Apache Shiro 是一个强大易用的 Java 安全框架,提供了认证.授权.加密和会话管理等功能,对于任何一个应用程序,Shiro 都可以提供全面的安全管理服务.并且相对于其他安全框架, ...

  2. mysql必知必会--检 索 数 据

    SELECT 语句 SQL语句是由简单的英语单词构成的.这些单词称 为关键字,每个SQL语句都是由一个或多个关键字构成的.大概,最经常 使用的SQL语句就是 SELECT 语句了.它的用途是从一个或多 ...

  3. 教你如何理解JAVA的I/O类库

    花括号MC(huakuohao-mc):关注JAVA基础编程及大数据,注重经验分享及个人成长. Java 的 I/O 流,说简单也简单,说复杂也复杂.复杂是因为进行一次常规的文件 I/O 操作通常要用 ...

  4. linux命令——find

    简介:find是Linux系统中的常用命令(应用程序)之一.它是用来在指定目录层次结构(指定目录的子目录以及子目录的子目录)中查找符合指定条件的文件和目录 一:语法结构 find [directory ...

  5. Django复制记录的方法

    最近的Django项目中有复制记录的需求.数据库里有一张名为Party的表,记录用户创建的party,现在要让用户能够复制一个新的party.本身非常简单的一个功能,但运行的时候出错了.我以为是复制过 ...

  6. linux---基础学习

    学习使用linux 偶然间看到一篇介绍linux的使用,于是看了看,整体看完,虽然看的有些懵✒,但还是坚持看完了基础部分,并做了一些摘要. man页面所属的分类标识 常用的是分类1和分类3 (1).用 ...

  7. mysql升级到5.7

    最近遇到一个问题,执行下列语句会报错: CREATE TABLE `t_user` ( `USER_ID` bigint() NOT NULL AUTO_INCREMENT COMMENT '用户ID ...

  8. #AcWing系列课程Level-2笔记——4. 浮点数二分算法

    浮点数二分算法 编写浮点数二分,记住下面的思路,代码也就游刃有余了! 1.首先找到数组的中间值,mid=(left+right)>>1,区间[left, right]被划分成[left, ...

  9. 【Android】java中调用JS的方法

    最近因为学校换了新的教务系统,想做一个模拟登陆功能,发现登陆的账号和密码有一个js脚本来进行加密 整理了一下java中执行JS的方法 智强教务 账号 密码 加密方法 var keyStr = &quo ...

  10. BundlePhobia

    1.BundlePhobia用于分析npm package的依赖.bundle后的大小.下载速度预估等等,帮助你在引用一个package之前了解引入该package的代价. 2.也可以将项目的pack ...