Data Constraint
n<=80000,所有数字的绝对值不超过5000000
Solution
这是一道分块的板题 但是并不是那么好写的
一般来说我们都按照根号n为块的大小进行分块
那么,对于某一个询问或者查找
就对于整块的部分打个标记
而对于边缘部分暴力处理
这道题目的时限给了8s
我们分块之后处理k小数就用二分来解决
这样的复杂度比较玄学
code
#include <cstdio>
#include <cstring>
#include <algorithm>
#define fo(i,a,b) for(i=a;i<=b;i++)
using namespace std;
const int N=80005,sz=300; //sz为块大小
struct edge{
int s,w,d;
} a[N];
int x,y,z,l,r,n,m,i,mid,j,t;
int s[sz],rr[sz],add[sz];
int read(){
int sum=0,p=1;
char c=getchar();
while (c<'0'||c>'9') {
if (c=='-') p=-1;
c=getchar();}
while (c>='0'&&c<='9') {
sum=sum*10+c-'0';
c=getchar();}
return sum*p;
}
inline bool cmp(edge a,edge b){ return a.d<b.d;}
inline int search(int h,int k){
int l,r,mid;
l=s[h],r=rr[h];
while (l<r-1){
mid=(l+r)>>1;
if (a[mid].d+add[h]<k) l=mid; else r=mid;
}
while (a[r].d+add[h]>=k&&r>=l) r--;
return r-s[h]+1;
}
inline int get(int x,int y,int k){
int l,r,i,ans;
ans=0;
l=(x+sz-1)/sz,r=(y+sz-1)/sz;
if (l==r){
fo(i,x,y) if (add[l]+a[a[i].s].d<k) ans++;
return ans;
}
fo(i,l+1,r-1) ans+=search(i,k);
fo(i,x,rr[l]) if (a[a[i].s].d+add[l]<k) ans++;
fo(i,s[r],y) if (a[a[i].s].d+add[r]<k) ans++;
return ans;
}
int main(){
freopen("1.in","r",stdin);
freopen("1.out","w",stdout);
n=read();
fo(i,1,n) a[i].d=read(),a[i].w=i;
fo(i,1,(n+sz-1)/sz){
s[i]=(i-1)*sz+1,rr[i]=min(i*sz,n);
sort(a+s[i],a+rr[i]+1,cmp);
}
fo(i,1,n) a[a[i].w].s=i;//a[i].s为a[i].w的一个反函数
//因为我们的数组经过了排序,所以更改x就等于更改a[a[x].s]
m=read();
while (m){
m--;
t=read(),x=read(),y=read(),z=read();
if (t==1){
l=(x+sz-1)/sz,r=(y+sz-1)/sz;
if (l==r){
fo(i,x,y) a[a[i].s].d+=z;
sort(a+s[l],a+rr[l]+1,cmp);
//注意这里的排序范围,整一个块都要重新排序,而不是x到y
fo(i,s[l],rr[l]) a[a[i].w].s=i;
} else {
fo(i,l+1,r-1) add[i]+=z;
fo(i,x,rr[l]) a[a[i].s].d+=z;
fo(i,s[r],y) a[a[i].s].d+=z;
sort(a+s[l],a+rr[l]+1,cmp),sort(a+s[r],a+rr[r]+1,cmp);
fo(i,s[l],rr[l]) a[a[i].w].s=i;
fo(i,s[r],rr[r]) a[a[i].w].s=i;
}
} else {
l=-5000000,r=5000000; //二分
while (l<r-1){
mid=(l+r)>>1;
if (get(x,y,mid)<z) l=mid; else r=mid;
}
if (get(x,y,l)<=z) r=l;
printf("%d\n",r);
}
}
}