BZOJ 2957:楼房重建(分块)
http://www.lydsy.com/JudgeOnline/problem.php?id=2957
题意:……
思路:对于每一个块,维护一个单调递增的斜率(因为小于前面的斜率的话是肯定看不见的),每次修改都暴力重建这个块,然后求和的时候可以二分查找当前的块比之前的块的最大斜率大的元素个数(注意精度调大一点),然后就可以得到答案了。(这么暴力感觉好爽啊,upper_bound()好方便啊)
1 #include <cstdio> 2 #include <cstring> 3 #include <algorithm> 4 #include <cmath> 5 using namespace std; 6 #define N 100010 7 #define INF 0x3f3f3f3f 8 typedef long long LL; 9 const double eps = 1e-10; 10 int n, m, sz, num, l[N], r[N], belong[N], cnt[N]; 11 double a[N], block[1010][1010]; 12 13 void Build() { 14 memset(a, 0, sizeof(a)); 15 memset(cnt, 0, sizeof(cnt)); 16 memset(block, 0, sizeof(block)); 17 sz = sqrt(n); 18 num = n / sz; if(n % sz) num++; 19 for(int i = 1; i <= num; i++) 20 l[i] = (i - 1) * sz + 1, r[i] = i * sz; 21 r[num] = n; 22 for(int i = 1; i <= n; i++) 23 belong[i] = (i - 1) / sz + 1; 24 } 25 26 void Update(int x) { // 暴力重建块 27 double tmp = 0.0; cnt[x] = 0; 28 for(int i = l[x]; i <= r[x]; i++) // 维护单调递增序列 29 if(tmp < a[i]) tmp = a[i], block[x][++cnt[x]] = a[i]; 30 } 31 32 int Query() { 33 int ans = 0; double tmp = 0.0; 34 for(int i = 1; i <= num; i++) { // 二分查找,注意精度 35 if(!cnt[i]) continue; 36 int now = cnt[i] - (upper_bound(block[i] + 1, block[i] + 1 + cnt[i], tmp + eps) - block[i] - 1); 37 if(now) tmp = block[i][cnt[i]]; 38 ans += now; 39 } 40 return ans; 41 } 42 43 int main() { 44 while(~scanf("%d%d", &n, &m)) { 45 Build(); 46 for(int i = 1; i <= m; i++) { 47 int id, w; 48 scanf("%d%d", &id, &w); 49 a[id] = (double)w / id; 50 Update(belong[id]); 51 printf("%d\n", Query()); 52 } 53 } 54 return 0; 55 }