线段树/树状数组(codeforces 1404C Fixed Point Removal)
Posted Kalzn
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了线段树/树状数组(codeforces 1404C Fixed Point Removal)相关的知识,希望对你有一定的参考价值。
题目链接
题意:给你一个长度为n的数组。
我们定义一种操作,如果数组中有某个数满足
a
i
=
i
a_i=i
ai=i,即值等于它的下标,你就可以删去它,它后面的元素将全部往前移动一格。
现在有m次查询,每次查询给你一对x,y。你要回答出,在不删除前x个和后y个元素的情况下,你最多可以进行多少次上述操作。
题解:
挺有意思的一道线段树。我们考虑离线,先把查询按照x排序。
我们先考虑:对于一个元素而言,如果它的值大于了它的下标,那么这个元素就肯定不可能被删除。那么我们现在设:
g
=
i
−
a
i
g=i-a_i
g=i−ai。即如果想要删除
a
i
a_i
ai。我们需要把它往前移多少位,那么这时,显然,如果在第i个元素之前可以删除的元素个数大于等于g,那么
a
i
a_i
ai也是一个可以删除的元素。(我们只要将前面的元素删除g个后,然后来删除
a
i
a_i
ai即可。)
我们离线后,x是递增的,那么这时我们考虑,在不断从前往后减去
a
x
a_x
ax元素影响后,怎么维护可删除点。
首先我们使用线段树维护数组:
v
a
l
[
i
]
=
I
N
F
c
n
t
i
<
i
−
a
i
∨
a
i
>
i
c
n
t
i
−
(
i
−
a
i
)
e
l
s
e
val[i]=\\left\\ \\beginaligned INF&&\\ cnt_i<i-a_i\\lor a_i>i\\\\ cnt_i-(i-a_i) && \\ else \\endaligned \\right.
val[i]=INFcnti−(i−ai) cnti<i−ai∨ai>i else
其中
c
n
t
i
cnt_i
cnti是第i个元素之前的可以删除的元素个数。
我们在考虑减去
a
x
a_x
ax的影响时,应该这么做:如果
a
x
a_x
ax是一个不可删除元素,则直接跳过。
如果
a
x
a_x
ax是个可删除元素,那么我们令其变成一个不可删除元素,令
v
a
l
[
x
]
=
I
N
F
val[x]=INF
val[x]=INF,然后将数组
v
a
l
val
val区间
[
x
+
1
,
n
]
[x+1,n]
[x+1,n]的值减一。然后寻找
v
a
l
val
val数组中第一个小于0的数的位置
a
k
a_k
ak,这个数一定是个可删除元素(不可删除元素的val都是INF)。我们把
a
k
a_k
ak设置为不可删除元素,令
v
a
l
[
k
]
=
I
N
F
val[k]=INF
val[k]=INF,然后将
v
a
l
val
val的区间
[
k
+
1
,
n
]
[k+1,n]
[k+1,n]减一。重复上述过程,直到
v
a
l
val
val中不存在小于0的元素。然后通过树状数组查询
[
x
,
y
]
[x,y]
[x,y]区间中有多少可删除元素即可。因为每个元素至多删除一次。所以时间复杂度为
O
(
n
l
o
g
n
+
m
)
O(nlogn+m)
O(nlogn+m)。
下面是ac代码:
// % everyone
#include <cstdio>
#include<iostream>
#include<cstring>
#include <map>
#include <queue>
#include <set>
#include <cstdlib>
#include <cmath>
#include <algorithm>
#include <vector>
#include <string>
#include <list>
#include <cctype>
#include <time.h>
namespace IO
double start_time = 0.0;
void ct() start_time = clock(); return;
void fast_cin() std::ios::sync_with_stdio(false); std::cin.tie();
void read_f(int flag = 0) freopen("0.in", "r", stdin); if(!flag) freopen("0.out", "w", stdout);
void run_time() std::cout << "\\nESC in : " << ( clock() - start_time ) * 1000.0 / CLOCKS_PER_SEC << "ms" << std::endl;
using namespace IO;
template <typename T>
bool bacmp(const T & a, const T & b) return a > b;
template <typename T>
bool pecmp(const T & a, const T & b) return a < b;
#define ll long long
#define ull unsigned ll
#define _min(x, y) ((x)>(y)?(y):(x))
#define _max(x, y) ((x)>(y)?(x):(y))
#define max3(x, y, z) ( max( (x), max( (y), (z) ) ) )
#define min3(x, y, z) ( min( (x), min( (y), (z) ) ) )
#define pr make_pair
#define pb push_back
using namespace std;
const int N = 3e5+5;
const int inf = 0x3f3f3f3f;
const int mod = 1000000007;
struct Node
int l, r;
int val, pos;
int laz;
tr[N<<2];
int su[N], val[N], c[N];
bool vis[N];
int n, m;
void add(int x, int val)
for (; x < N; x += x & -x) c[x] += val;
int askc(int x)
if (x == 0) return 0;
int res = 0;
for (; x; x -= x & -x) res += c[x];
return res;
inline void update(int p, int v)
tr[p].val += v;
tr[p].laz += v;
inline void spread(int p)
if (tr[p].laz == 0) return;
update(p<<1, tr[p].laz);
update(p<<1|1, tr[p].laz);
tr[p].laz = 0;
inline void pushup(int p)
if (tr[p<<1].val <= tr[p<<1|1].val)
tr[p].val = tr[p<<1].val;
tr[p].pos = tr[p<<1].pos;
else
tr[p].val = tr[p<<1|1].val;
tr[p].pos = tr[p<<1|1].pos;
void build(int p, int l, int r)
tr[p].l = l; tr[p].r = r;
tr[p].laz = 0;
if (l == r)
tr[p].val = val[l]; tr[p].pos = l; return;
int mid = (l + r) >> 1;
build(p<<1, l, mid);
build(p<<1|1, mid+1, r);
pushup(p);
void changek(int p, int pos, int v)
if (tr[p].l == tr[p].r)
tr[p].val = v;
return;
spread(p);
int mid = (tr[p].l +tr[p].r) >> 1;
if (pos <= mid) changek(p<<1, pos, v);
else changek(p<<1|1, pos, v);
pushup(p);
return;
void change(int p, int l, int r, int v)
if (l > r) return;
if (l<=tr[p].l && tr[p].r <= r)
update(p, v); return;
spread(p);
int mid = (tr[p].l + tr[p].r) >> 1;
if (l <= mid) change(p<<1, l, r, v);
if (r > mid) change(p<<1|1, l, r, v);
pushup(p);
int ask(int p)
if (tr[p].l == tr[p].r)
return tr[p].pos;
spread(p);
if (tr[p<<1].val < 0) return ask(p<<1);
else if (tr[p<<1|1].val 以上是关于线段树/树状数组(codeforces 1404C Fixed Point Removal)的主要内容,如果未能解决你的问题,请参考以下文章
非原创codeforces 1070C Cloud Computing 线段树&树状数组
[树状数组][权值线段树] Codeforces 1093E Intersection of Permutations
Codeforces 889F Letters Removing(二分 + 线段树 || 树状数组)
Codeforces 1139F Dish Shopping 树状数组套平衡树 || 平衡树