loj#6279. 数列分块入门 3

#6279. 数列分块入门 3

题目:传送门 

简要题意:

   给出一个长为 n 的数列,以及 n 个操作,操作涉及区间加法,询问区间内小于某个值 x 的前驱(比其小的最大元素)。


题解:

   有点无耻的用一波set,其实就和分块2差不多嘛,找一下大于等于该元素的数,位置减一就ok


代码:

 1 #include<cstdio>
 2 #include<cstring>
 3 #include<cstdlib>
 4 #include<cmath>
 5 #include<algorithm>
 6 #include<vector>
 7 #include<set>
 8 using namespace std;
 9 int n,a[110000],ba[110000];
10 int block,pos[110000];
11 set<int> s[110];
12 void update(int l,int r,int c)
13 {
14     for(int i=l;i<=min(pos[l]*block,r);i++)
15     {
16         s[pos[i]].erase(a[i]);
17         a[i]+=c;
18         s[pos[i]].insert(a[i]);
19     }
20     if(pos[l]!=pos[r])
21         for(int i=(pos[r]-1)*block+1;i<=r;i++)
22         {
23             s[pos[i]].erase(a[i]);
24             a[i]+=c;
25             s[pos[i]].insert(a[i]);
26         }
27     for(int i=pos[l]+1;i<=pos[r]-1;i++)ba[i]+=c;
28 }
29 void sol(int l,int r,int c)
30 {
31     int ans=-1;
32     for(int i=l;i<=min(pos[l]*block,r);i++)if(a[i]+ba[pos[i]]<c)ans=max(ans,a[i]+ba[pos[i]]);
33     if(pos[l]!=pos[r])
34         for(int i=(pos[r]-1)*block+1;i<=r;i++)
35             if(a[i]+ba[pos[i]]<c)
36                 ans=max(ans,a[i]+ba[pos[i]]);
37     for(int i=pos[l]+1;i<=pos[r]-1;i++)
38     {
39         int x=c-ba[i];
40         set<int>::iterator it=s[i].lower_bound(x);
41         if(it==s[i].begin())continue;
42         it--;
43         ans=max(ans,*it+ba[i]);
44     }
45     printf("%d
",ans);
46 }
47 int main()
48 {
49     memset(pos,0,sizeof(pos));memset(ba,0,sizeof(ba));
50     scanf("%d",&n);for(int i=1;i<=n;i++)scanf("%d",&a[i]);
51     block=1000;for(int i=1;i<=n;i++){pos[i]=(i-1)/block+1;s[pos[i]].insert(a[i]);}
52     for(int i=1;i<=n;i++)
53     {
54         int opt,l,r,c;
55         scanf("%d%d%d%d",&opt,&l,&r,&c);
56         if(opt==0)update(l,r,c);
57         else sol(l,r,c);
58     }
59     return 0;
60 }
原文地址:https://www.cnblogs.com/CHerish_OI/p/8580579.html