給你一個長度爲\(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); } } }