给你一个长度为\(n\)的序列\(a_i\)和\(m\)次操做,要支持两种操做:node
\(1\ l\ r\ flag\):将\([l,r]\)内的数排序,\(flag=1\)表示排成升序,不然是降序ios
\(2\ l\ r\):询问\([l,r]\)内的数的乘积的最高位是多少c++
数据范围:\(n,m<=2*10^5\),\(1\leq a_i\leq n\)ide
首先考虑怎么处理询问:一个很棒的idea是转成维护\(lg\),取对数以后乘法就被转成了加法,咱们只要维护区间\(lg\)的和\(sum\),还原的话整数部分不须要管,因此只要取\(pow(10,sum-\lfloor sum \rfloor)\)的首位便可ui
那么剩下的就是如何处理区间排序操做了idea
显然的一点是:被\(op1\)操做过的区间必定是有序的,那么一个大胆的想法是把操做过而变得有序的区间内的数放在一块儿维护,具体来讲就是对于每个操做过的区间种一棵权值线段树(固然要动态开点),这样咱们就能够快速查询每一块中的前缀和或者后缀和,升序降序直接整块记录一下查询的时候判断一下就行了spa
而后咱们再用一棵大线段树来维护整个序列,具体来讲就是将每一块(也就是每一颗权值线段树)的根节点的信息(\(lg\)和)存到这一块最左边的那个位置上,其余位置所有为\(0\)code
这样一来咱们只要实现一个线段树的分离操做和合并操做、以及快速肯定一个位置\(p\)属于哪个块(这个能够经过大线段树维护一个区间块头的\(min\)来实现)就能够了排序
修改的时候就一头一尾判一下是否须要split,而后中间一段一直合并;询问就一直跳\(l\)的块就行了,主要考虑\(l\)不是块头的状况ip
时间复杂度的话。。因为修改每次最多增长一个块,因此总复杂度是均摊的,具体的话势能分析一下(然而由于我比较菜因此只能口胡==),每次操做是均摊\(log\)的,总的就是常数巨大的\(O(nlogn)\)
#include<iostream> #include<cstdio> #include<cstring> #include<cmath> #define ldb long double #define Pr pair<int,int> #define mp make_pair using namespace std; const int N=2e5+10; int a[N],dir[N];//1==up 0==down ldb lg[N]; int n,m,ans; namespace Seg{/*{{{*/ const int N=::N*40; int ch[N][2],rt[::N],cnt[N]; int pool[N]; ldb sum[N]; int n,tot,tp; void pushup(int x){ cnt[x]=cnt[ch[x][0]]+cnt[ch[x][1]]; sum[x]=sum[ch[x][0]]+sum[ch[x][1]]; } void init(int _n){n=_n; tot=tp=0;} void del(int x){pool[++tp]=x;} int newnode(){ tot=tp?pool[tp--]:++tot; cnt[tot]=sum[tot]=0; ch[tot][0]=ch[tot][1]=0; return tot; } void _insert(int &x,int d,int lx,int rx,ldb delta){ if (!x) x=newnode(); ++cnt[x]; sum[x]+=delta; if (lx==rx) return; int mid=lx+rx>>1; if (d<=mid) _insert(ch[x][0],d,lx,mid,delta); else _insert(ch[x][1],d,mid+1,rx,delta); } void insert(int x,int d){_insert(rt[x],d,1,n,lg[d]);} void merge(int &x,int y){ if (!x||!y){x=x+y; return;} merge(ch[x][0],ch[y][0]); merge(ch[x][1],ch[y][1]); sum[x]+=sum[y]; cnt[x]+=cnt[y]; del(y); } Pr _split(int x,int d,int lx,int rx){ if (!x||!d) return mp(0,x); if (cnt[x]==d) return mp(x,0); int nw=newnode(); if (lx==rx){ sum[nw]=lg[lx]*d; cnt[nw]=d; sum[x]-=sum[nw]; cnt[x]-=cnt[nw]; return mp(nw,x); } int lcnt=cnt[ch[x][0]],mid=lx+rx>>1; Pr tmp; if (d<=lcnt){ tmp=_split(ch[x][0],d,lx,mid); ch[x][0]=tmp.second; ch[nw][0]=tmp.first; pushup(x); pushup(nw); return mp(nw,x); } else{ tmp=_split(ch[x][1],d-lcnt,mid+1,rx); ch[x][1]=tmp.first; ch[nw][1]=tmp.second; pushup(x); pushup(nw); return mp(x,nw); } } Pr split(int x,int d){ Pr ret; if (dir[x]) ret=_split(rt[x],d,1,n); else{ ret=_split(rt[x],cnt[rt[x]]-d,1,n); swap(ret.first,ret.second); } return ret; } ldb _query(int x,int k,int lx,int rx){ if (!x||!k) return 0; if (lx==rx) return k*lg[lx]; int lcnt=cnt[ch[x][0]],mid=lx+rx>>1; if (k>=lcnt) return sum[ch[x][0]]+_query(ch[x][1],k-lcnt,mid+1,rx); return _query(ch[x][0],k,lx,mid); } ldb query(int x,int k){ if (dir[x]) return _query(rt[x],k,1,n); else return sum[rt[x]]-_query(rt[x],cnt[rt[x]]-k,1,n); } }/*}}}*/ namespace Seg2{/*{{{*/ const int N=::N*4; int ch[N][2],mn[N]; ldb sum[N]; int n,tot; void pushup(int x){ sum[x]=sum[ch[x][0]]+sum[ch[x][1]]; mn[x]=min(mn[ch[x][0]],mn[ch[x][1]]); } void _build(int x,int l,int r){ if (l==r){ sum[x]=Seg::sum[Seg::rt[l]]; mn[x]=l; return; } int mid=l+r>>1; ch[x][0]=++tot; _build(ch[x][0],l,mid); ch[x][1]=++tot; _build(ch[x][1],mid+1,r); pushup(x); } void build(int _n){n=_n; tot=1; _build(1,1,n);} void _update(int x,int d,int lx,int rx){ if (lx==rx){ mn[x]=Seg::rt[lx]?lx:n+1; sum[x]=Seg::sum[Seg::rt[lx]]; return; } int mid=lx+rx>>1; if (d<=mid) _update(ch[x][0],d,lx,mid); else _update(ch[x][1],d,mid+1,rx); pushup(x); } void update(int d){_update(1,d,1,n);} int _get_p(int x,int d,int lx,int rx){ if (mn[x]>d) return -1; if (lx==rx) return lx; int mid=lx+rx>>1,ret=-1; if (d>mid) ret=_get_p(ch[x][1],d,mid+1,rx); if (d<=mid||ret==-1) ret=_get_p(ch[x][0],d,lx,mid); return ret; } int get_p(int d){return _get_p(1,d,1,n);}//the hd which d belongs to ldb _query(int x,int l,int r,int lx,int rx){ if (l<=lx&&rx<=r) return sum[x]; int mid=lx+rx>>1; if (r<=mid) return _query(ch[x][0],l,r,lx,mid); else if (l>mid) return _query(ch[x][1],l,r,mid+1,rx); else return _query(ch[x][0],l,mid,lx,mid)+_query(ch[x][1],mid+1,r,mid+1,rx); } ldb query(int l,int r){return _query(1,l,r,1,n);} }/*}}}*/ ldb get_val(int x,int l,int r){ ldb tmp1=l-1?Seg::query(x,l-1):0; ldb tmp2=Seg::query(x,r); return tmp2-tmp1; } void prework(int n){ for (int i=1;i<=n;++i) lg[i]=log10(i); //for (int i=1;i<=n;++i) lg[i]=i; Seg::init(n); for (int i=1;i<=n;++i) Seg::insert(i,a[i]); Seg2::build(n); } void modify(int l,int r,int op){ using Seg::rt; int tmp,hd,sz; Pr pr; hd=Seg2::get_p(r); sz=Seg::cnt[rt[hd]]; if (hd+sz-1>r){//split r pr=Seg::split(hd,r-hd+1); rt[hd]=pr.first; rt[r+1]=pr.second; dir[r+1]=dir[hd]; Seg2::update(r+1); } tmp=0; while (hd>l){//merge mid Seg::merge(tmp,rt[hd]); rt[hd]=0; Seg2::update(hd); hd=Seg2::get_p(r); } if (hd<l){//split l pr=Seg::split(hd,l-hd); rt[hd]=pr.first; rt[l]=pr.second; Seg2::update(hd); } Seg::merge(rt[l],tmp); dir[l]=op; Seg2::update(l); } int query(int l,int r){ using Seg::rt; int hd=Seg2::get_p(r); ldb ret; if (hd<=l){//same ret=get_val(hd,l-hd+1,r-hd+1); } else{ ret=Seg2::query(l,hd-1); ret+=get_val(hd,1,r-hd+1); hd=Seg2::get_p(l); if (hd<l)//l --> not hd ret+=get_val(hd,l-hd+1,Seg::cnt[rt[hd]]); } ret=pow(10,ret-floor(ret)); return (int)ret; } int main(){ #ifndef ONLINE_JUDGE freopen("a.in","r",stdin); #endif int op,l,r,dir; scanf("%d%d",&n,&m); for (int i=1;i<=n;++i) scanf("%d",a+i); prework(n); for (int i=1;i<=m;++i){ scanf("%d%d%d",&op,&l,&r); if (op==1){ scanf("%d",&dir); modify(l,r,dir); } else{ ans=query(l,r); printf("%d\n",ans); } } }