CF 1405E Fixed Point Removal【线段树上二分】
CF 1405E Fixed Point Removal【线段树上二分】
题意:
给定长度为\(n\)的序列\(A\),每次操作可以把\(A_i = i\)(即值等于其下标)的数删掉,然后剩下的数组拼接起来,问最多能删多少个数
\(q\)次独立询问,每次把前\(x\)个数和\(后\)后\(y\)个数置为\(n+1\)之后解决上述问题
题解:
先不考虑把前\(x\)个数和后\(y\)个数置成\(n+1\)的情况
首先我们可以想到的是把所有数的值减去其下标,定义\(B_i = A_i - i\),那么对于\(B_i=0\)的位置,一开始就是可以删除的,当删掉了第\(i\)个数之后,之前的数的下标没有变化,之后的数下标都减了\(1\),即对于所有\(j>i\)的\(B_j\)变成了\(B_j+1\),也就可能存在新的\(B_j=0\)的情况
根据上面的事实,那么一开始\(B_i>0\)的这些值永远也删不掉,且为了删除最多的数,每次肯定选择最右边的\(B_i=0\)的值进行删除(如果存在下标\(i,j\)且\(i<j,B_i=B_j=0\),如果先删除\(i\),那么\(j\)就删不掉了)
现在有一个推论:对于某个位置\(i\),如果\(B_i<=0\),那么在它之前至少存在\(-B_i\)个数被删掉,这个数就也可以被删除
那么对于每个位置\(i\),满足\(B_i\le0\),存在一个左边界\(l\),只要第\(l\)个元素能够删除,那么第\(i\)个元素也能被删除
左边界\(l\)需要满足只考虑\([l,i)\)区间的元素的情况下,可删除元素大于等于\(-B_i\)个,如果\(B_i=0\)显然\(l=i\)
那么对于每个存在左边界的\(i\)需要做的就是在\(l\)的位置加上\(1\),每个位置的值就表示以这个点为左边界的情况下能删除多少个数,找\(l\)的方法可以二分之后算区间和或者直接在线段树上二分,前者复杂度\(O(\log^2n)\)后者复杂度\(O(\log n)\)
考虑先把询问按右边界从小到大排序(即\(y\)从大到小排序),遍历每个询问,更新到\(i=n-y\)的位置,然后计算\([x+1,n-y]\)的区间和就好了
排序是因为要防止当前不合法的点对左边界产生贡献
view code
#pragma GCC optimize("O3")
#pragma GCC optimize("Ofast,no-stack-protector")
#include<bits/stdc++.h>
using namespace std;
#define INF 0x3f3f3f3f
#define endl "\n"
#define LL long long int
#define vi vector<int>
#define vl vector<LL>
#define all(V) V.begin(),V.end()
#define sci(x) scanf("%d",&x)
#define scl(x) scanf("%lld",&x)
#define scs(s) scanf("%s",s)
#define pii pair<int,int>
#define pll pair<LL,LL>
#ifndef ONLINE_JUDGE
#define cout cerr
#endif
#define cmax(a,b) ((a) = (a) > (b) ? (a) : (b))
#define cmin(a,b) ((a) = (a) < (b) ? (a) : (b))
#define debug(x) cerr << #x << " = " << x << endl
function<void(void)> ____ = [](){ios_base::sync_with_stdio(false); cin.tie(0); cout.tie(0);};
template <typename T> vector<T>& operator << (vector<T> &__container, T x){ __container.push_back(x); return __container; }
template <typename T> ostream& operator << (ostream &out, vector<T> &__container){ for(T _ : __container) out << _ << ' '; return out; }
const int MAXN = 3e5+7;
int n, q, A[MAXN];
pair<pii,int> Q[MAXN];
struct SegmentTree{
int sum[MAXN<<2], l[MAXN<<2], r[MAXN<<2];
#define ls(rt) rt << 1
#define rs(rt) rt << 1 | 1
void build(int L, int R, int rt = 1){
l[rt] = L; r[rt] = R;
sum[rt] = 0;
if(l[rt] + 1 == r[rt]) return;
int mid = (L + R) >> 1;
build(L,mid,ls(rt)); build(mid,R,rs(rt));
}
void modify(int pos, int x, int rt = 1){
sum[rt] += x;
if(l[rt] + 1 == r[rt]) return;
int mid = (l[rt] + r[rt]) >> 1;
if(pos<mid) modify(pos,x,ls(rt));
else modify(pos,x,rs(rt));
}
int qsum(int L, int R, int rt = 1){
if(L>=r[rt] or l[rt]>=R) return 0;
if(L<=l[rt] and r[rt]<=R) return sum[rt];
return qsum(L,R,ls(rt)) + qsum(L,R,rs(rt));
}
int qpos(int x, int rt = 1){
if(l[rt] + 1 == r[rt]) return l[rt];
if(sum[rs(rt)]>=x) return qpos(x,rs(rt));
else return qpos(x-sum[rs(rt)],ls(rt));
}
}ST;
int ret[MAXN];
void solve(){
sci(n); sci(q);
for(int i = 1; i <= n; i++) sci(A[i]), A[i] -= i;
for(int i = 1; i <= q; i++){
sci(Q[i].first.first); sci(Q[i].first.second);
Q[i].second = i;
}
sort(Q+1,Q+1+q,[&](pair<pii,int> &a, pair<pii,int> &b){ return a.first.second > b.first.second; });
int cur = 1, tot = 0;
ST.build(0,n+1);
for(int i = 1; i <= q; i++){
while(cur<=n-Q[i].first.second){
if(A[cur]==0) ST.modify(cur,1), tot++;
else if(A[cur]<0 and -A[cur]<=tot) ST.modify(ST.qpos(-A[cur]),1), tot++;
cur++;
}
ret[Q[i].second] = ST.qsum(Q[i].first.first+1,cur);
}
for(int i = 1; i <= q; i++) cout << ret[i] << endl;
}
int main(){
#ifndef ONLINE_JUDGE
freopen("Local.in","r",stdin);
freopen("ans.out","w",stdout);
#endif
solve();
return 0;
}
CF 1405E Fixed Point Removal【线段树上二分】的更多相关文章
- LOJ 3059 「HNOI2019」序列——贪心与前后缀的思路+线段树上二分
题目:https://loj.ac/problem/3059 一段 A 选一个 B 的话, B 是这段 A 的平均值.因为 \( \sum (A_i-B)^2 = \sum A_i^2 - 2*B \ ...
- 贪心+离散化+线段树上二分。。。 Samara University ACM ICPC 2016-2017 Quarterfinal Qualification Contest G. Of Zorcs and Axes
题目链接:http://codeforces.com/gym/101149/problem/G 题目大意:给你n对数字,为(a[i], b[i]),给你m对数字,为(w[i], c[i]).给n对数字 ...
- 【BZOJ】4293: [PA2015]Siano 线段树上二分
[题意]给定n棵高度初始为0的草,每天每棵草会长高a[i],m次收割,每次在d[i]天将所有>b[i]的草收割到b[i],求每次收割量.n<=500000. [算法]线段树上二分 [题解] ...
- hdu 5930 GCD 线段树上二分/ 强行合并维护信息
from NOIP2016模拟题28 题目大意 n个点的序列,权值\(<=10^6\) q个操作 1.单点修改 2.求所有区间gcd中,不同数个数 分析 1.以一个点为端点,向左或向右的gcd种 ...
- HDU 4747 Mex【线段树上二分+扫描线】
[题意概述] 一个区间的Mex为这个区间没有出现过的最小自然数,现在给你一个序列,要求求出所有区间的Mex的和. [题解] 扫描线+线段树. 我们在线段树上维护从当前左端点开始的前缀Mex,显然从左到 ...
- [NOIP2015模拟10.27] [JZOJ4270] 魔道研究 解题报告(动态开点+权值线段树上二分)
Description “我希望能使用更多的魔法.不对,是预定能使用啦.最终我要被大家称呼为大魔法使.为此我决定不惜一切努力.”——<The Grimoire of Marisa>雾雨魔理 ...
- 【洛谷5537】【XR-3】系统设计(哈希_线段树上二分)
我好像国赛以后就再也没有写过 OI 相关的博客 qwq Upd: 这篇博客是 NOIP (现在叫 CSP 了)之前写的,但是咕到 CSP 以后快一个月才发表 -- 我最近这么咕怎么办啊 -- 题目 洛 ...
- 5.4 省选模拟赛 修改 线段树优化dp 线段树上二分
LINK:修改 题面就不放了 大致说一下做法.不愧是dls出的题 以前没见过这种类型的 不过还是自己dp的时候写丑了. 从这道题中得到一个结论 dp方程要写的优美一点 不过写的过丑 优化都优化不了. ...
- 9 16 模拟赛&关于线段树上二分总结
1 考试时又犯了一个致命的错误,没有去思考T2的正解而是去简单的推了一下式子开始了漫漫找规律之路,不应该这样做的 为了得到规律虽然也打了暴力 但是还是打了一些不必要的程序 例如求组合数什么的比较浪费时 ...
随机推荐
- LeetCode 371两数之和
题目描述: 不使用运算符 + 和 - ,计算两整数 a .b 之和. 思路: 既然不能使用运算符操作就要考虑到,位运算的加法. 加法有进位的时候和不进位的时候 ...
- 使用Jenkins+Pipline 持构建自动化部署之安卓源码打包、测试、邮件通知
一.引言 Jenkins 2.x的精髓是Pipeline as Code,那为什么要用Pipeline呢?jenkins1.0也能实现自动化构建,但Pipeline能够将以前project中的配置信息 ...
- 【Oracle】add_months()函数介绍
add_months 函数主要是对日期函数进行操作,举例子进行说明 add_months 有两个参数,第一个参数是日期,第二个参数是对日期进行加减的数字(以月为单位的) 如:3个月以后的时间,可以用下 ...
- python协程爬取某网站的老赖数据
import re import json import aiohttp import asyncio import time import pymysql from asyncio.locks im ...
- 写给 Linux 初学者的一封信
大家好,我是肖邦. 这篇文章是写给 Linux 初学者的,我会分享一些作为初学者应该知道的一些东西,这些内容都是本人从事 Linux 开发工作多年的心得体会,相信会对初学者有所帮助.如果你是 Linu ...
- AOP面向切面编程(使用注解和使用配置文件)
Aop(面向切面编程) 使用注解的方式: 加入相应的jar包: com.springsource.org.aopalliance-1.0.0.jar com.springsource.org.aspe ...
- 全网最详细的PyCharm+Anaconda的安装。
目录 PyCharm的安装 一.下载安装包 1.安装网站 2.在导航栏输入网址回车 3.点击 DOWNLOAD. 4.它有专业版和社区版,我们下载社区版就可以使用了.(专业版要收费) 二.安装过程 5 ...
- uni-app开发经验分享四: 实现文字复制到选择器中
这里分享一个我经常用到的一个方法,主要是用来复制文字内容,具体代码如下: var that=this; if(!document){ uni.setClipboardData({ data:复制的值, ...
- 通过电脑浏览器调试真机h5兼容问题
前言 在h5开发过程中,起初我们使用PC浏览器的手机模式打开开发中的页面,并使用控制台进行调试,但实际真机兼容性问题无法调试到:在这种情况下,我们通常使用vConsole(即移动端的控制台)来调试,但 ...
- 两种方式,花五分钟就能构建一个 Spring Boot 应用
前言 Spring Boot 的好处自然不必多说,对于想要从事 Java 工作的朋友们来说,可谓是必学的技能. 在我看来,它的优势就是多快好省. 功能多,很多常用的能力都有集成: 接入快,简单的几行代 ...