描述
给一个长为N的数列,有M次操作,每次操作是以下两种之一:
(1)修改数列中的一个数
(2)求数列中有多少个数比它前面的数都大
题解
不会就去参考了一下前辈的题解,说是楼房重建的原题,又去参考了楼房重建的题解(滑稽)。
对于本题,建立线段树,区间记录最大值和有多少数比前面的数都大的数的个数sum。
考虑合并区间时第二个信息,如果右区间最大值小于等于左区间最大值,那么直接取左区间信息,应该比较显然右区间的任何一个元素都比左区间最大值小。
不然的话就要把左区间最大值val带入右区间查询,如果现在val>=左区间最大值,那么查询右区间即可;不然进入左区间查询,然后+sum[rt]-sum[ls],为什么可以不查询右区间呢?因为sum已经记录了整个区间的信息,sum[rt]-sum[ls]就是右区间中比前面的数都大的数的个数(对于整个区间),现在val<左区间最大值,所以就是答案。
如果非要查询val应该就要改成左区间最大值。
#include<bits/stdc++.h> using namespace std; const int maxn=100005; int n,m,cnt; int root,ls[maxn<<1],rs[maxn<<1],sum[maxn<<1]; int h[maxn<<1],a[maxn]; template<class T>inline void read(T &x){ x=0;int f=0;char ch=getchar(); while(!isdigit(ch)) {f|=(ch=='-');ch=getchar();} while(isdigit(ch)) {x=(x<<1)+(x<<3)+(ch^48);ch=getchar();} x= f ? -x : x ; } int query(int rt,int l,int r,int val){ if(l==r) return h[rt]>val; int mid=(l+r)>>1; if(val>=h[ls[rt]]) return query(rs[rt],mid+1,r,val); return query(ls[rt],l,mid,val)+sum[rt]-sum[ls[rt]]; } int update(int rt,int l,int r){ if(h[ls[rt]]>=h[rs[rt]]) return sum[ls[rt]]; return sum[ls[rt]]+query(rs[rt],((l+r)>>1)+1,r,h[ls[rt]]); } void build(int &rt,int l,int r){ rt=++cnt; if(l==r){ h[rt]=a[l]; sum[rt]=1; return ; } int mid=(l+r)>>1; build(ls[rt],l,mid); build(rs[rt],mid+1,r); sum[rt]=update(rt,l,r); h[rt]=max(h[ls[rt]],h[rs[rt]]); } void modify(int rt,int l,int r,int pos,int val){ if(l==r){ h[rt]=val; sum[rt]=1; return ; } int mid=(l+r)>>1; if(pos<=mid) modify(ls[rt],l,mid,pos,val); else modify(rs[rt],mid+1,r,pos,val); sum[rt]=update(rt,l,r); h[rt]=max(h[ls[rt]],h[rs[rt]]); } int main(){ read(n);read(m); for(int i=1;i<=n;i++){ int x;read(x); a[i]=x; } build(root,1,n); for(int i=1;i<=m;i++){ char op[2]; scanf("%s",op); if(op[0]=='Q') printf("%d ",sum[1]); else { int pos,val; read(pos);read(val); modify(1,1,n,pos,val); } } }
对于楼房重建把每个位置的权值弄成斜率即可。
#include<bits/stdc++.h> using namespace std; const int maxn=100005; int n,m,cnt; int root,ls[maxn<<1],rs[maxn<<1],sum[maxn<<1]; double h[maxn<<1]; template<class T>inline void read(T &x){ x=0;int f=0;char ch=getchar(); while(!isdigit(ch)) {f|=(ch=='-');ch=getchar();} while(isdigit(ch)) {x=(x<<1)+(x<<3)+(ch^48);ch=getchar();} x= f ? -x : x ; } int query(int rt,int l,int r,double val){ if(l==r) return h[rt]>val; int mid=(l+r)>>1; if(val>h[ls[rt]]) return query(rs[rt],mid+1,r,val); return query(ls[rt],l,mid,val)+sum[rt]-sum[ls[rt]]; } int update(int rt,int l,int r){ if(h[ls[rt]]>=h[rs[rt]]) return sum[ls[rt]]; return sum[ls[rt]]+query(rs[rt],((l+r)>>1)+1,r,h[ls[rt]]); } void build(int &rt,int l,int r){ rt=++cnt; if(l==r) return ; int mid=(l+r)>>1; build(ls[rt],l,mid); build(rs[rt],mid+1,r); } void modify(int rt,int l,int r,int pos,double val){ if(l==r){ h[rt]=val; sum[rt]=1; return ; } int mid=(l+r)>>1; if(pos<=mid) modify(ls[rt],l,mid,pos,val); else modify(rs[rt],mid+1,r,pos,val); sum[rt]=update(rt,l,r); h[rt]=max(h[ls[rt]],h[rs[rt]]); } int main(){ read(n);read(m); build(root,1,n); for(int i=1;i<=m;i++){ int pos,val; read(pos);read(val); modify(1,1,n,pos,1.0*val/pos); printf("%d ",sum[1]); } }