LibreOj 6279数列分块入门 3 练习了一下set
Posted 6262369sss
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了LibreOj 6279数列分块入门 3 练习了一下set相关的知识,希望对你有一定的参考价值。
题目链接:https://loj.ac/problem/6279
推荐博客:https://blog.csdn.net/qq_36038511/article/details/79725027
这题区间查询某个数字x的前驱(区间里比x小的最大的数),我用的是二分,自己手写二分的时候一直用的是没有排序的数组,好无语,后面又用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; else return 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]; else return 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 ",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; else return 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 ",ans); } } return 0; }
以上是关于LibreOj 6279数列分块入门 3 练习了一下set的主要内容,如果未能解决你的问题,请参考以下文章