LibreOj 6279数列分块入门 3 练习了一下set
生活随笔
收集整理的這篇文章主要介紹了
LibreOj 6279数列分块入门 3 练习了一下set
小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.
題目鏈接:https://loj.ac/problem/6279
推薦博客:https://blog.csdn.net/qq_36038511/article/details/79725027
這題區(qū)間查詢某個數(shù)字x的前驅(qū)(區(qū)間里比x小的最大的數(shù)),我用的是二分,自己手寫二分的時候一直用的是沒有排序的數(shù)組,好無語,后面又用set做了一遍,熟系一下set。
#include<iostream> #include<cstring> #include<algorithm> #include<queue> #include<map> #include<stack> #include<cmath> #include<vector> #include<set> #include<cstdio> #include<string> #include<deque> using namespace std; typedef long long LL; #define eps 1e-8 #define INF 0x3f3f3f3f #define maxn 50005*2 /*struct point{int u,w; }; bool operator <(const point &s1,const point &s2) {if(s1.w!=s2.w)return s1.w>s2.w;elsereturn s1.u>s2.u; }*/ int n,m,k,t,block; int a[maxn],tag[maxn],lump[maxn]; vector<int>ve[510]; void update(int x) {ve[x].clear();//把第x塊原來的值清除 for(int i=(x-1)*block+1;i<=min(x*block,n);i++)//這里要加min,因為第x塊可能是最后一塊并且是不完整的 ve[x].push_back(a[i]);//把增加了的值重新壓入 sort(ve[x].begin(),ve[x].end());//排序 } void add(int l,int r,int c) {for(int i=l;i<=min(lump[l]*block,r);i++)//暴力更新左邊不完整的塊 a[i]+=c;update(lump[l]);//更新值并且重新排序 if(lump[l]!=lump[r]){for(int i=(lump[r]-1)*block+1;i<=r;i++)//暴力更新右邊不完整的塊a[i]+=c;update(lump[r]);}for(int i=lump[l]+1;i<=lump[r]-1;i++)tag[i]+=c;} int binary_search(int x,int w) {int l=0,r=ve[x].size()-1;int pos=-INF;while(l<=r){int mid=(l+r)/2;if(ve[x][mid]>=w){r=mid-1;pos=r;}else{l=mid+1;pos=mid;}}if(pos>=0&&pos<ve[x].size()&&ve[x][pos]<w)return ve[x][pos];elsereturn INF; } int find(int l,int r,int c) {int ans=-1;for(int i=l;i<=min(lump[l]*block,r);i++)//在左邊不完整的塊里查找 {if(a[i]+tag[lump[l]]<c)ans=max(ans,a[i]+tag[lump[l]]);}if(lump[l]!=lump[r]){for(int i=(lump[r]-1)*block+1;i<=r;i++)//在右邊的不完整的塊里查找 {if(a[i]+tag[lump[r]]<c)ans=max(ans,a[i]+tag[lump[r]]);} }for(int i=lump[l]+1;i<=lump[r]-1;i++)//在中間的完整的并且有序的塊里二分查找 {int t=c-tag[i]; /*int s=lower_bound(ve[i].begin(),ve[i].end(),t)-ve[i].begin();if(s!=0&&tag[i]+ve[i][s-1]<c)ans=max(ve[i][s-1]+tag[i],ans);*/int s=binary_search(i,t);if(s+tag[i]<c)ans=max(ans,s+tag[i]);}return ans; } int main() {scanf("%d",&n);fill(tag,tag+maxn-1,0);for(int i=0;i<=n;i++)ve[i].clear();block=sqrt(n);for(int i=1;i<=n;i++){scanf("%d",&a[i]);lump[i]=(i-1)/block+1;ve[lump[i]].push_back(a[i]);}for(int i=1;i<=lump[n];i++)//把每一塊的值進行排序 sort(ve[i].begin(),ve[i].end());for(int j=1;j<=n;j++){int op,l,r,c;scanf("%d%d%d%d",&op,&l,&r,&c);if(op==0)add(l,r,c);else{int ans=find(l,r,c);printf("%d\n",ans);}}return 0; }用set的代碼:
#include<iostream> #include<cstring> #include<algorithm> #include<queue> #include<map> #include<stack> #include<cmath> #include<vector> #include<set> #include<cstdio> #include<string> #include<deque> using namespace std; typedef long long LL; #define eps 1e-8 #define INF 0x3f3f3f3f #define maxn 50005*2 /*struct point{int u,w; }; bool operator <(const point &s1,const point &s2) {if(s1.w!=s2.w)return s1.w>s2.w;elsereturn s1.u>s2.u; }*/ int n,m,k,t,block; int a[maxn],tag[maxn],lump[maxn]; set<int>se[510]; void add(int l,int r,int c) {for(int i=l;i<=min(lump[l]*block,r);i++)//暴力更新左邊不完整的塊 {se[lump[l]].erase(a[i]);a[i]+=c;se[lump[l]].insert(a[i]);}if(lump[l]!=lump[r]){for(int i=(lump[r]-1)*block+1;i<=r;i++)//暴力更新右邊不完整的塊 {se[lump[r]].erase(a[i]);a[i]+=c;se[lump[r]].insert(a[i]);}}for(int i=lump[l]+1;i<=lump[r]-1;i++)tag[i]+=c;} int find(int l,int r,int c) {int ans=-1;for(int i=l;i<=min(lump[l]*block,r);i++)//在左邊不完整的塊里查找 {if(a[i]+tag[lump[l]]<c)ans=max(ans,a[i]+tag[lump[l]]);}if(lump[l]!=lump[r]){for(int i=(lump[r]-1)*block+1;i<=r;i++)//在右邊的不完整的塊里查找 {if(a[i]+tag[lump[r]]<c)ans=max(ans,a[i]+tag[lump[r]]);} }for(int i=lump[l]+1;i<=lump[r]-1;i++)//在中間的完整的并且有序的塊里二分查找 {int t=c-tag[i]; set<int>::iterator it=se[i].lower_bound(t);if(it==se[i].begin())continue;it--;ans=max(ans,tag[i]+(*it));}return ans; } int main() {scanf("%d",&n);fill(tag,tag+maxn-1,0);for(int i=0;i<=500;i++)se[i].clear();block=sqrt(n);for(int i=1;i<=n;i++){scanf("%d",&a[i]);lump[i]=(i-1)/block+1;se[lump[i]].insert(a[i]);}for(int j=1;j<=n;j++){int op,l,r,c;scanf("%d%d%d%d",&op,&l,&r,&c);if(op==0)add(l,r,c);else{int ans=find(l,r,c);printf("%d\n",ans);}}return 0; }?
轉(zhuǎn)載于:https://www.cnblogs.com/6262369sss/p/9736601.html
總結(jié)
以上是生活随笔為你收集整理的LibreOj 6279数列分块入门 3 练习了一下set的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 设计模式:讲在设计模式之前
- 下一篇: javascript底层练习