[洛谷P2801]教主的魔法
阿新 • • 發佈:2017-10-27
大於 時間復雜度 tchar har 個數 數列 ems 重新 題目
題目大意:有n個數,q個操作。操作有兩種:①把一段區間所有數加上p;②查詢一段區間內大於等於p的元素的個數。
解題思路:詢問次數少,可以用分塊解決。
將所有數分成$\sqrt{n}$塊,對每一塊進行排序。
用a數組存原來的數列,b數組存排完序後的數列。
查詢時,對左右兩個塊中的數據暴力查詢,中間的由於整塊訪問並排完序,直接二分查找即可。
修改數據時,對左右兩個塊中的數據暴力修改,並且更新b數組(重新排序),對中間的,由於相對大小不變,直接打上標記即可。
修改時,最多對兩個塊進行排序,時間復雜度$O(\sqrt{n}\log_2\sqrt{n})$。
查詢時,最多對所有塊都進行二分查找,時間復雜度$O(\sqrt{n}\log_2\sqrt{n})$。
故總時間復雜度$O(q\sqrt{n}\log_2\sqrt{n})$。
C++ Code:
#include<cstdio> #include<algorithm> #include<cmath> #include<cstring> #include<cctype> using namespace std; int a[1000005],b[1000005]; int n,q,size,l[1005],r[1005],blocks,add[1005],inbk[1000005]; char s[4]; inline int readint(){ char c=getchar(); for(;!isdigit(c);c=getchar()); int d=0; for(;isdigit(c);c=getchar()) d=(d<<3)+(d<<1)+(c^‘0‘); return d; } void chan(int blk){ for(int i=l[blk];i<=r[blk];++i) b[i]=a[i]; sort(b+l[blk],b+r[blk]+1); } int main(){ n=readint();q=readint(); size=(int)(sqrt(n)+0.00000001); blocks=0; l[1]=1; for(int i=1;i<=n;++i){ a[i]=b[i]=readint(); inbk[i]=blocks+1; if(i%size==0){ r[++blocks]=i; l[blocks+1]=i+1; } } if(n%size) r[++blocks]=n; for(int i=1;i<=blocks;++i) sort(b+l[i],b+r[i]+1); memset(add,0,sizeof add); while(q--){ scanf("%s",s); if(s[0]==‘M‘){ int L=readint(),R=readint(),p=readint(); if(L>R)L^=R^=L^=R; int lft=inbk[L],rgt=inbk[R]; if(lft==rgt){ for(int i=L;i<=R;++i)a[i]+=p; chan(lft); }else{ for(int i=lft+1;i<rgt;++i)add[i]+=p; for(int i=L;i<=r[lft];++i)a[i]+=p; for(int i=l[rgt];i<=R;++i)a[i]+=p; chan(lft); chan(rgt); } }else{ int L=readint(),R=readint(),p=readint(),ans=0; int lft=inbk[L],rgt=inbk[R]; if(lft==rgt){ for(int i=L;i<=R;++i) if(a[i]+add[lft]>=p)++ans; }else{ for(int i=lft+1;i<rgt;++i) ans+=r[i]-(lower_bound(b+l[i],b+r[i]+1,p-add[i])-b-1); for(int i=L;i<=r[lft];++i) if(a[i]+add[lft]>=p)++ans; for(int i=l[rgt];i<=R;++i) if(a[i]+add[rgt]>=p)++ans; } printf("%d\n",ans); } } return 0; }
[洛谷P2801]教主的魔法