Description
给出一个长度为 n n 的序列,如果 ai a i 是前 i i 个数中的严格最大值则算一个贡献,有种操作,操作不继承,每次操作将 ap a p 改成 q q ,操作后查询贡献
Input
第一行一整数表示用例组数,每组用例首先输入两个整数 n,m n , m 表示序列长度和操作数,之后输入 n n 个整数,最后 m m 行每行两个整数表示查询将 ap a p 变成 q q 后序列的贡献
Output
输出每次修改后该序列的贡献
Sample Input
1
5 3
1 2 3 4 4
1 5
5 5
2 3
Sample Output
1
5
3
Solution
首先可以通过预处理前缀和最大值知道没有修改操作时的合法位置,这些位置的高度显然严格递增.
同时注意到,如果一个位置前方有超过一个位置的高度不小于这个位置的高度,那么除非修改这个位置的高度使其大于前面高度的最大值,否则这个位置不可能合法,而如果一个位置前方只有一个位置的高度不小于这个位置的高度,也即前面有一个位置“阻碍”了当前位置合法,那么这个位置可能通过修改这个阻碍位置的高度变合法,用树状数组可以维护一个位置前方不小于该位置高度的位置数量,对每个位置记录其“阻碍”的位置序列,可知这 n n 个序列总规模也不会超过.
最后考虑将第 p p 个位置高度变为,如果是高度增加,首先不影响前 p−1 p − 1 个位置已经合法的位置,也不会影响之前就不合法的位置(除了 p p 位置本身),会影响的是第个位置之后的合法位置中高度不超过 q q 的,故在之前维护的合法位置序列中二分即可知道位置后依然合法的位置个数;如果是高度减小,那么首先不会影响除 p p 位置之外的所有合法位置,对位置单独判断即可,会影响的是被 p p 位置阻碍的位置序列,该序列中所有大于的位置会变合法,故在这个序列中二分即可知道变合法的位置个数,单次查询时间复杂度 O(logn) O ( l o g n )
总时间复杂度 O((n+m)logn) O ( ( n + m ) l o g n )
Code
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<vector>
using namespace std;
typedef long long ll;
#define maxn 100005
int T,n,m,a[maxn],h[maxn],mx[maxn],pos[maxn],num[maxn];
vector<int>H,g[maxn];
struct BIT
{
#define lowbit(x) (x&(-x))
int b[maxn],n;
void init(int _n)
{
n=_n;
for(int i=1;i<=n;i++)b[i]=0;
}
void update(int x,int v)
{
while(x<=n)
{
b[x]+=v;
x+=lowbit(x);
}
}
int query(int x)
{
int ans=0;
while(x)
{
ans+=b[x];
x-=lowbit(x);
}
return ans;
}
}bit;
int main()
{
scanf("%d",&T);
while(T--)
{
scanf("%d%d",&n,&m);
mx[0]=0;
H.clear();
num[0]=0;
for(int i=1;i<=n;i++)
{
scanf("%d",&a[i]);
if(mx[i-1]>=a[i])pos[i]=pos[i-1];
else pos[i]=i;
mx[i]=max(mx[i-1],a[i]);
if(a[i]>mx[i-1])H.push_back(a[i]),num[i]=num[i-1]+1;
else num[i]=num[i-1];
h[i-1]=a[i];
}
sort(h,h+n);
int res=unique(h,h+n)-h;
bit.init(res);
for(int i=1;i<=n;i++)g[i].clear();
for(int i=1;i<=n;i++)
{
int t=lower_bound(h,h+res,a[i])-h+1;
t=res+1-t;
int num=bit.query(t);
if(num==1)g[pos[i-1]].push_back(a[i]);
bit.update(t,1);
}
while(m--)
{
int p,q;
scanf("%d%d",&p,&q);
if(q>=a[p])
{
int pos=upper_bound(H.begin(),H.end(),q)-H.begin();
pos=H.size()-pos;
pos=min(pos,((int)H.size()-num[p-1]));
if(q>mx[p-1])pos++;
printf("%d\n",num[p-1]+pos);
}
else
{
int pos=upper_bound(g[p].begin(),g[p].end(),q)-g[p].begin();
pos=g[p].size()-pos;
if(a[p]>mx[p-1])
{
if(q<=mx[p-1])pos--;
}
else
{
if(q>mx[p-1])pos++;
}
printf("%d\n",H.size()+pos);
}
}
}
return 0;
}