题目传送门
题意:
n个数组成的序列a。a初始时全是0。
n个数组成的序列b。b是排列。
操作和询问总共是q次。
操作:a序列的 区间都加1。
询问: 。
数据范围: 。
题解:
这道题乍一看暴力是 。
但是观察一下,发现b序列的排列有一个作用:保证了答案是 。
这样就可以暴力了。
但是需要一些技巧:a序列加1,相当于b序列减1,当b序列出现0时,答案加1,并且这个数变成原来的数。
线段树维护区间最小值和区间和,当区间最小值是0时,暴力统计答案,暴力更新。
区间最小值指的是b序列的区间最小值。区间和指的是b序列对答案的贡献的区间和。
感受:
签到题都不会写。
无语。
代码:
#include<bits/stdc++.h>
using namespace std ;
typedef long long ll ;
const int maxn = 1e5 + 5 ;
const int maxm = 1e6 + 5 ;
const ll mod = 998244353 ;
int n , q , b[maxn] , c[maxn] ;
char s[10] ;
int sum[maxn << 2] , add[maxn << 2] ;
int min1[maxn << 2] ;
int ls(int x)
{
return x << 1 ;
}
int rs(int x)
{
return x << 1 | 1 ;
}
void push_up(int p)
{
min1[p] = min(min1[ls(p)] , min1[rs(p)]) ;
sum[p] = sum[ls(p)] + sum[rs(p)] ;
}
void build(int id , int l , int r)
{
add[id] = 0 ;
if(l == r){sum[id] = 0 , min1[id] = b[l] ; return ;}
int mid = (l + r) >> 1 ;
build(ls(id) , l , mid) ;
build(rs(id) , mid + 1 , r) ;
push_up(id) ;
}
void f(int id , int l , int r , int k)
{
add[id] = add[id] + k ;
min1[id] = min1[id] + k ;
}
void push_down(int id , int l , int r)
{
int mid = (l + r) >> 1 ;
f(ls(id) , l , mid , add[id]) ;
f(rs(id) , mid + 1 , r , add[id]) ;
add[id] = 0 ;
}
void regain(int id , int l , int r)
{
int mid = (l + r) / 2 ;
if(l == r)
{
sum[id] ++ ;
min1[id] = c[l] ;
return ;
}
push_down(id , l , r) ;
if(min1[ls(id)] == 0) regain(ls(id) , l , mid) ;
if(min1[rs(id)] == 0) regain(rs(id) , mid + 1 , r) ;
push_up(id) ;
}
void update(int id , int l , int r , int x , int y , int k)
{
if(x <= l && r <= y)
{
f(id , l , r , k) ;
return ;
}
push_down (id , l , r) ;
int mid = (l + r) >> 1 ;
if(x <= mid) update(ls(id) , l , mid , x , y , k) ;
if(y > mid) update(rs(id) , mid + 1 , r , x , y , k) ;
push_up(id) ;
}
int query(int id , int l , int r , int x , int y)
{
int ans = 0 ;
if(x <= l && r <= y) return sum[id] ;
int mid = (l + r) >> 1 ;
push_down(id , l , r) ;
if(x <= mid) ans += query(ls(id) , l , mid , x , y) ;
if(y > mid) ans += query(rs(id) , mid + 1 , r , x , y) ;
return ans ;
}
int main()
{
while(scanf("%d%d" , &n , &q) != EOF)
{
for(int i = 1 ; i <= n ; i ++) scanf("%d" , &b[i]) , c[i] = b[i] ;
build(1 , 1 , n) ;
while(q --)
{
int l , r ;
scanf("%s%d%d" , s , &l , &r) ;
if(s[0] == 'a') update(1 , 1 , n , l , r , -1) , regain(1 , 1 , n) ;
else printf("%d\n" , query(1 , 1 , n , l , r)) ;
}
}
return 0 ;
}