C. Fixed Point Removal
题目大意
给一个数组,如果ai == i 那就可以删除ai , 之后后面的就可以并上来,也就是后面的下标都-1.
问最多可以删除多少个。
有m组询问 每次询问输入 x,y 就是 把前x个和后y个变成n + 1, 后,答案是多少。
瞎bb
单纯理一下思路。。
如果没有查询
可以注意到删掉后面的,对前面的没有影响。如果当前的 ai > i 那必不可能删除这个值了。所以应该从后往前删,如果当前的 ai <= i 并且 前面删除的个数大于等于i - ai 那这个值就一定可以删除。
有查询
有查询操作怎么办?
把前x个后y个变成n + 1也就是前x 个和后y个不能删除了, 所以就是只考虑x + 1 ~ n - y + 1区间里的数。
考虑可以删除这个点的时候左端点的最大值是多少?
为什么考虑这个东西? 因为这个东西是单调的。
也就是说: 如果左端点是2的时候,可以删除这个点。那么左端点是1的时候,一定可以删除这个点。这个应该很好理解。。因为只要前面可以删除的数量大于等于i - a[i] 就好了, 如果2 ~ i - 1删除的数量大于等于 i - a[i] 那么1 ~ i - 1可以删除的数量就肯定大于等于i - a[i]
那么这个题就比较好做了,离线,按询问的 r 排个序,二分找出可以删除这个点的最左端的下标,然后把前面的下标都+1,就好。
询问的时候直接询问l点的权值。
区间修改(变成单点修改),单点询问,可以树状数组。
#include<algorithm>
#include<iostream>
#include <cstdio>
#include <string>
#include <queue>
#include <cstring>
#include <stack>
#include <map>
#include <bitset>
#include <set>
#include <unordered_set>
#include <climits>
using namespace std;
typedef long long ll;
typedef pair<int,int> pii;
typedef pair<ll,ll> pll;
typedef pair<double,double> pdd;
typedef unsigned long long ull;
typedef unordered_set<int>::iterator sit;
#define st first
#define sd second
#define mkp make_pair
#define pb push_back
void tempwj(){freopen("hash.in","r",stdin);freopen("hash.out","w",stdout);}
ll gcd(ll a,ll b){return b == 0 ? a : gcd(b,a % b);}
ll qpow(ll a,ll b,ll mod){a %= mod;ll ans = 1;while(b > 0){if(b & 1)ans = ans * a % mod;a = a * a % mod;b >>= 1;}return ans;}
struct cmp{bool operator()(const pii & a, const pii & b){return a.second > b.second;}};
int lb(int x){return x & -x;}
//friend bool operator < (Node a,Node b) 重载
const int inf = INT_MAX;
const ll INF = 0x3f3f3f3f3f3f3f3f;
const ll mod = 1e9+7;
const int maxn = 4e5+10;
const int M = 1e6+10;
int ans[maxn];
int tree[maxn];
int n;
int a[maxn];
std::vector<pii> vv[maxn];
void add(int x,int num)
{
while(x <= n)
{
tree[x] += num;
x += lb(x);
}
}
int query(int x)
{
int ans =0 ;
while(x > 0)
{
ans += tree[x];
x -= lb(x);
}
return ans;
}
int main()
{
int m;
scanf("%d%d",&n,&m);
for(int i = 1; i <= n; i ++ )
scanf("%d",&a[i]);
for (int i = 1; i <= m; i ++ )
{
int x,y;
scanf("%d %d",&x,&y);
vv[n - y].pb(mkp(x + 1,i));
}
for(int i = 1; i <= n; i ++ )
{
a[i] = i - a[i];
}
for (int i = 1; i <= n; i ++ )
{
if(a[i] >= 0)
{
// printf("123\n");
int l = 1, r = i;
while(l < r)
{
int mid = l + r + 1 >> 1;
if(query(mid) >= a[i])
l = mid;
else
r = mid - 1;
}
// printf("%d\n", l);
if(query(l) >= a[i])
{
add(1,1);
add(l + 1,-1);
// printf("111\n");
}
}
// for (int j =1 ; j<= n; j ++ )
// printf("%d ",query(j));
// printf("\n");
for (int j = 0; j < vv[i].size(); j ++ )
{
ans[vv[i][j].sd] = query(vv[i][j].st);
// printf("%d %d\n",vv[i][j].st,vv[i][j].sd);
}
// printf("11111111111\n");
}
for (int i = 1; i <= m; i ++ )
printf("%d\n",ans[i]);
}