分块 (寻找区间小于k的最大值

一题简单的分块操作,听说要用set卡就打了下但是感觉貌似不用,好像vector处理也能过。

题目链接https://loj.ac/problem/6280

  1 #include<bits/stdc++.h>
  2 using namespace std;
  3 typedef long long ll;
  4 const int maxn = 1e5+10;
  5 const int inf = 0x3f3f3f3f;
  6 int dir[10][10] = {{1,0},{-1,0},{0,1},{0,-1}};
  7 int pos[maxn*2], a[maxn*2], lz[maxn*2], minn[maxn];
  8 int l, r, opt, t, n, c, k;
  9 set<int> s[2010];  //用从大到小就是 set<int,greater<int> > s[2010];
 10 
 11 inline int read()
 12 {
 13     char ch = getchar(); ll k = 0, f = 1;
 14     while(ch < '0' || ch > '9') {if(ch == '-') f = -1; ch = getchar();}
 15     while(ch >= '0' && ch <= '9') {k = (k << 1) + (k << 3) + ch - '0'; ch = getchar();}
 16     return k * f;
 17 }
 18 
 19 inline void reset(int x)
 20 {
 21     s[x].clear();
 22     s[x].insert(a + (x - 1) * t + 1, a + min(x * t, n) + 1);  //更新set
 23 }
 24 
 25 inline void inser(int l, int r, int c)
 26 {
 27     if(pos[l] == pos[r])
 28     {
 29         for(int i = l; i <= r; ++i) a[i] += c;
 30         reset(pos[l]);
 31     }
 32 
 33     else
 34     {
 35         for(int i = l; i <= pos[l] * t; ++i) a[i] += c;
 36         reset(pos[l]);
 37         for(int i = (pos[r] - 1) * t + 1; i <= r; ++i) a[i] += c;
 38         reset(pos[r]);
 39         for(int i = pos[l] + 1; i <= pos[r] - 1; ++i) lz[i] += c;
 40     }
 41 
 42 }
 43 
 44 inline int findy(int l, int r, int c)
 45 {
 46     int ans = -inf;
 47     if(pos[l] == pos[r])
 48     {
 49         for(int i = l; i <= r; ++i)
 50         {
 51             if(lz[pos[l]] + a[i] < c && lz[pos[l]] + a[i] > ans) ans = lz[pos[l]] + a[i];
 52         }
 53 
 54     }
 55 
 56     else
 57     {
 58         for(int i = l; i <= pos[l] * t; ++i) if(lz[pos[l]] + a[i] < c && lz[pos[l]] + a[i] > ans) ans = lz[pos[l]] + a[i];
 59         for(int i = (pos[r] - 1) * t + 1; i <= r; ++i) if(lz[pos[r]] + a[i] < c && lz[pos[r]] + a[i] > ans) ans = lz[pos[r]] + a[i];
 60         for(int i = pos[l] + 1; i <= pos[r] - 1; i++)
 61         {
 62             int x = c - lz[i];
 63             set<int>::iterator it = s[i].lower_bound(x);
 64             if(it == s[i].begin())  continue;   //值得注意的是如果用*lower_bound没找到返回的不一定是0,此时就难判断
 65             it--;
 66             ans = max(ans, *it + lz[i]);
 67         }
 68 
 69     }
 70 
 71     return ans;
 72 }
 73 
 74 int main()
 75 {
 76     n = read();
 77     for(int i = 1; i <= n; ++i) a[i] = read();
 78     t = sqrt(n);
 79 
 80     for(int i = 1; i <= n; ++i)
 81     {
 82         pos[i] = (i - 1)/t + 1;
 83         s[pos[i]].insert(a[i]);
 84     }
 85 
 86     for(int i = 1; i <= n; ++i)
 87     {
 88         opt = read(); l = read(); r = read(); c = read();
 89         if(opt == 0) inser(l, r, c);
 90         else
 91         {
 92             k = findy(l, r, c);
 93             if(k != -inf) cout<<k<<endl;
 94             else cout<<-1<<endl;
 95         }
 96 
 97     }
 98 
 99     return 0;
100 }

其中有很多地方代码都可以更加简洁一些,比如维护个L,R数组。但我可能顺着思路写就有点死脑筋,导致检查起来也不太好看。

用*lower_bound()进行判断容易卡(别问我为什么知道。。

第一篇随笔,不周到之处见谅

posted @ 2020-07-31 00:15  YanMingA  阅读(187)  评论(0编辑  收藏  举报