H Sequence
题意:
n个数,有两个操作,操作1是将第x位换成y
操作2是问包含第x位的序列中,x为最小数的序列有多少个
题解:
一开始想用树状数组来做,但是感觉树状数组太弱了,貌似不够用
赶紧换成线段树,(不想打线段树)
如何统计序列有多少个,比如指定第x位,在第x位之前有a个数比他大,有b个数比他小,那答案不就是a*b,但是注意,这个a和b必须分别是连续的,也就是在x之前有a个数是连续的,且与x相连的大于x的数,不然x就不是序列中最小的数了
那怎么计算a和b?
我们利用二分,第一次找x左边,第二次找x的右边
操作1好说,线段树常规操作
详细看代码
代码:
#include<bits/stdc++.h>
using namespace std;
const int maxn=2e5+9;
int n,m;
int a[maxn];
int tree[maxn*4];
void bulid(int rt,int l,int r)
{
if(l==r)
{
tree[rt]=a[l];
return ;
}
int mid=(l+r)>>1;
bulid(rt*2,l,mid);
bulid(rt*2+1,mid+1,r);
tree[rt]=min(tree[rt*2],tree[rt*2+1]);
}
void update(int rt,int l,int r,int x,int y)
{
if(l==r)
{
tree[rt]=y;
return ;
}
int mid=(l+r)>>1;
if(x<=mid)
update(rt*2,l,mid,x,y);
else
update(rt*2+1,mid+1,r,x,y);
tree[rt]=min(tree[rt*2],tree[rt*2+1]);
}
int query(int rt,int l,int r,int ql,int qr)
{
if(ql<=l&&qr>=r)
{
return tree[rt];
}
int mid=(l+r)>>1;
int ans=1e9+9;
if(ql<=mid)ans=min(ans,query(rt*2,l,mid,ql,qr));
if(qr>mid)ans=min(ans,query(rt*2+1,mid+1,r,ql,qr));
return ans;
}
int main()
{
cin>>n>>m;
for(int i=1;i<=n;i++)cin>>a[i];
bulid(1,1,n);
for(int i=1;i<=m;i++)
{
int opt;
cin>>opt;
if(opt==1)
{
int x,y;
cin>>x>>y;
update(1,1,n,x,y);
a[x]=y;
}
else
{
int x;
cin>>x;
int nl,nr;
int l=1,r=x;
while(l<r)
{
int mid=(l+r)>>1;
if(query(1,1,n,mid,x)>=a[x])r=mid;
else l=mid+1;
}
nl=x-l+1;
l=x,r=n+1;
while(l<r)
{
int mid=(l+r)>>1;
if(query(1,1,n,x,mid)<a[x])r=mid;
else l=mid+1;
}
l--;
nr=l-x+1;
cout<<1ll*nl*nr<<endl;
}
}
}
京公网安备 11010502036488号