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; } } }