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的正解而是去简单的推了一下式子开始了漫漫找规律之路,不应该这样做的 为了得到规律虽然也打了暴力 但是还是打了一些不必要的程序 例如求组合数什么的比较浪费时 ...
随机推荐
- sql查询速度慢分析及如何优化查询
原因分析后台数据库中数据过多,未做数据优化数据请求-解析-展示处理不当 网络问题提高数据库查询的速度方案SQL 查询速度慢的原因有很多,常见的有以下几种:1.没有索引或者没有用到索引(查询慢最常见的问 ...
- 几幅图,拿下 HTTPS
我很早之前写过一篇关于 HTTP 和 HTTPS 的文章,但对于 HTTPS 介绍还不够详细,只讲了比较基础的部分,所以这次我们再来深入一下 HTTPS,用实战抓包的方式,带大家再来窥探一次 HTTP ...
- Spring Security OAuth2.0认证授权四:分布式系统认证授权
Spring Security OAuth2.0认证授权系列文章 Spring Security OAuth2.0认证授权一:框架搭建和认证测试 Spring Security OAuth2.0认证授 ...
- CentOS | python3.7安装指南
前言: centos系统本身默认安装有python2.x,版本x根据不同版本系统有所不同 可通过 python --V 或 python --version 查看系统自带的python版本 有一些系统 ...
- Python基础语法2-数据类型
一,数字. 2. 字符串类型 3.列表 4.元组 5.集合 6.字典 7.数据类型转换: 8.序列操作
- 【Oracle】查看oracle用户相关权限
系统权限 SELECT * FROM DBA_SYS_PRIVS WHERE GRANTEE = 'CHAXUN' UNION ALL SELECT * FROM DBA_SYS_PRIVS WHER ...
- CTFHub - Misc(流量分析)
数据库类流量: MySQL流量: 1.下载附件,是一个.pcap文件,用wireshark分析, 2.搜索ctfhub字段,即可得到flag, flag: ctfhub{mysql_is_S0_E4s ...
- kaggle新手如何在平台学习大神的代码
原创:数据臭皮匠 [导读]Kaggle ,作为听说它很牛X但从未接触过的同学,可能仅仅了解这是一个参加数据挖掘比赛的网站,殊不知Kaggle也会有赛题相关的数据集, 比如我们熟知的房价预测.泰坦尼克 ...
- 给HTML页面设置自己的icon
原因: 不知道为什么,SpringBoot中自动设置icon失效了. 解决方法: 在head标签中添加自己想要使用的icon图片.后缀使用图片格式,不要使用.ico. <link href=&q ...
- 使用Swagger2
一.Swagger2是什么? Swagger 是一个规范和完整的框架,用于生成.描述.调用和可视化 RESTful 风格的 Web 服务. 优点: 及时性 (接口变更后,能够及时准确地通知相关前后端开 ...