HYSBZ 2957 分块

 

题目链接:http://www.lydsy.com/JudgeOnline/problem.php?id=2957

题意:中文题面

思路: 来自此博客

首先明确问题,对于每栋楼房的斜率K=H/X,问题就是问有多少个楼房的K比前面所有楼房的K都要大。

这题树套树当然可以,但是挺麻烦的,本渣觉得最简单就是分块……

将N个楼房分成T块,不断维护每个块内楼房的可视序列,如一个块内楼房的高度分别为(3 1 4 2 6 7)那么这个块内楼房的可视序列就是(3 4 6 7)(注意不同的块内是不干扰的,如第一个块可视序列为(3 4 6),第二块的序列可以是(5 7 8))

对于每个修改,我们只需对每个块内的楼房暴力维护可视序列就行了,O(N/T)

对于每个询问,我们只需一个块一个块看,不断维护到目前为止的可视序列中K的最大值kmax(不在可视序列内的楼房的K值一定不大),那么对于查询每个块的时候,可以二分可视序列找到第一个大于kmax的位置,若没有则这个块的所有楼房都不可见,如果存在,那么这个位置后的此块中的可视序列楼房都能看见,那么就更新答案和kmax,不断往后做

#define _CRT_SECURE_NO_DEPRECATE
#include<stdio.h>  
#include<string.h>  
#include<cstring>
#include<algorithm>  
#include<queue>  
#include<math.h>  
#include<time.h>
#include<vector>
#include<iostream>
#include<map>
using namespace std;
typedef long long int LL;
const int MAXN = 100000 + 10;
int belong[MAXN], block, num, L[MAXN], R[MAXN];
int n, m;
double h[MAXN];
vector<double>Bh[MAXN];
void build(){
    block = int(sqrt(n + 0.5));
    num = n / block; if (n%block){ num++; }
    for (int i = 1; i <= num; i++){
        Bh[i].clear();
        L[i] = (i - 1)*block + 1; R[i] = i*block;
    }
    R[num] = n;
    for (int i = 1; i <= n; i++){
        belong[i] = ((i - 1) / block) + 1;
    }
}
void modify(int pos, int val){
    Bh[belong[pos]].clear(); h[pos] = double(val) / pos;
    for (int i = L[belong[pos]]; i <= R[belong[pos]]; i++){
        if (i == L[belong[pos]]){
            Bh[belong[pos]].push_back(h[i]); continue;
        }
        if (h[i]>Bh[belong[pos]][Bh[belong[pos]].size() - 1]){
            Bh[belong[pos]].push_back(h[i]);
        }
    }
}
int query(){
    int ans = 0;
    double maxh = 0;
    for (int i = 1; i <= num; i++){
        int pos = upper_bound(Bh[i].begin(), Bh[i].end(), maxh) - Bh[i].begin();
        if (pos != Bh[i].size()){
            ans += Bh[i].size() - pos;
            maxh = Bh[i][Bh[i].size() - 1];
        }
    }
    return ans;
}
int main(){
//#ifdef kirito
//    freopen("in.txt", "r", stdin);
//    freopen("out.txt", "w", stdout);
//#endif
//    int start = clock();
    while (~scanf("%d%d", &n, &m)){
        memset(h,0,sizeof(h));
        build();
        for (int i = 1; i <= m; i++){
            int pos, hei;
            scanf("%d%d", &pos, &hei); 
            modify(pos, hei);
            printf("%d\n", query());
        }
    }
//#ifdef LOCAL_TIME
//    cout << "[Finished in " << clock() - start << " ms]" << endl;
//#endif
    return 0;
}

 

posted @ 2016-10-10 13:23  キリト  阅读(311)  评论(0编辑  收藏  举报