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【线段树上二分】的更多相关文章

  1. LOJ 3059 「HNOI2019」序列——贪心与前后缀的思路+线段树上二分

    题目:https://loj.ac/problem/3059 一段 A 选一个 B 的话, B 是这段 A 的平均值.因为 \( \sum (A_i-B)^2 = \sum A_i^2 - 2*B \ ...

  2. 贪心+离散化+线段树上二分。。。 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对数字 ...

  3. 【BZOJ】4293: [PA2015]Siano 线段树上二分

    [题意]给定n棵高度初始为0的草,每天每棵草会长高a[i],m次收割,每次在d[i]天将所有>b[i]的草收割到b[i],求每次收割量.n<=500000. [算法]线段树上二分 [题解] ...

  4. hdu 5930 GCD 线段树上二分/ 强行合并维护信息

    from NOIP2016模拟题28 题目大意 n个点的序列,权值\(<=10^6\) q个操作 1.单点修改 2.求所有区间gcd中,不同数个数 分析 1.以一个点为端点,向左或向右的gcd种 ...

  5. HDU 4747 Mex【线段树上二分+扫描线】

    [题意概述] 一个区间的Mex为这个区间没有出现过的最小自然数,现在给你一个序列,要求求出所有区间的Mex的和. [题解] 扫描线+线段树. 我们在线段树上维护从当前左端点开始的前缀Mex,显然从左到 ...

  6. [NOIP2015模拟10.27] [JZOJ4270] 魔道研究 解题报告(动态开点+权值线段树上二分)

    Description “我希望能使用更多的魔法.不对,是预定能使用啦.最终我要被大家称呼为大魔法使.为此我决定不惜一切努力.”——<The Grimoire of Marisa>雾雨魔理 ...

  7. 【洛谷5537】【XR-3】系统设计(哈希_线段树上二分)

    我好像国赛以后就再也没有写过 OI 相关的博客 qwq Upd: 这篇博客是 NOIP (现在叫 CSP 了)之前写的,但是咕到 CSP 以后快一个月才发表 -- 我最近这么咕怎么办啊 -- 题目 洛 ...

  8. 5.4 省选模拟赛 修改 线段树优化dp 线段树上二分

    LINK:修改 题面就不放了 大致说一下做法.不愧是dls出的题 以前没见过这种类型的 不过还是自己dp的时候写丑了. 从这道题中得到一个结论 dp方程要写的优美一点 不过写的过丑 优化都优化不了. ...

  9. 9 16 模拟赛&关于线段树上二分总结

    1 考试时又犯了一个致命的错误,没有去思考T2的正解而是去简单的推了一下式子开始了漫漫找规律之路,不应该这样做的 为了得到规律虽然也打了暴力 但是还是打了一些不必要的程序 例如求组合数什么的比较浪费时 ...

随机推荐

  1. DHCP.md

    DHCP 主配置文件   从 /usr/share/doc/dhcp 复制 dhcpd.conf.sample 到/etc/dhcp下                                  ...

  2. PHP SDK短信接口

    /** * sdk 短信接口 * @param $tel 手机号 * @param $content 短信内容 * @return bool */ public function telSDK($te ...

  3. PAT天梯赛练习 L3-004 肿瘤诊断 (30分) 三维BFS

    题目分析: 可能是我的理解能力比较差,在读题的时候一直以为所有的切片是可以排列组合的,并不是按照输入顺序就定死的,那么这题就变得十分的复杂啦~~~~~,查看的题解之后发现所有的切片并没有所谓的自由组合 ...

  4. SpringBoot入门 简单搭建和使用

    前言 差不多两年前,那个时候我准备要做毕业设计了,才第一次知道java有框架这种东西,在网上找了好多SSM的教程,那会儿真的是Spring+SpringMVC+MyBatis搭建的,印象极深的是还要写 ...

  5. JavaFX之班级未交作业统计

    前言 最近转移了系统平台,用上了Ubuntu1804版本系统,原来用C#写的Windows窗体软件也不能用了,而且自己在班级上每周都需要收作业,所以写了这个软件.这篇博客主要记录这个JavaFX应用的 ...

  6. 1.8V转3V,1,8V转3.3V电源芯片的规格书参数

    1.8V电平如何稳压稳定输出3V或者3.3V,就需要用到1.8V转3V,1,8V转3.3V电源芯片,就PW5100(低功耗,外围简单),PW5200A是可调输出电压,可以输出电压根据外围电阻来设置命令 ...

  7. Python安装教程之anaconda篇

    [导读]我们知道,Python的功能非常强大.那么对于迫切想学习Python的新手同学来说,第一件事情可能需要了解python是什么?能用来做什么?语法结构是怎样的?这些我们几句话很难介绍清楚,后续会 ...

  8. 关于java并发场景下,HttpServletRequst中session丢失问题

    使用场景: 在list数据进来之后使用安全数组    Lists.newCopyOnWriteArrayList() 进行了   parallelStream  并行处理,在接口中进行了登录者信息接口 ...

  9. 忒修斯的Mac

    我有一台Mac笔记本,用了快6年了,当初买它的时候还借了几千块. 三年前,它的屏幕坏了,修理的方式就是直接换屏,而换屏其实就是上半部分连壳带屏幕整个换掉,简单的说:另一台电脑的上半身嫁接过来. 今年, ...

  10. python(pymysql操作数据库)

    第一种方式 import pymysql # 打开数据库连接 db = pymysql.connect(host="192.168.88.11", user="root& ...