楼房重建
不会,所以写写,然后发现还不会,遂先学然后写博客
楼房重建 (Luogu P4198)
发现原问题可以等价为每次在序列上修改一个值,询问有多少个点的权值严格大于之前所有点。
我们考虑利用线段树,线段树每个节点肯定得维护对于当前区间的答案,然后你就会发现我们只会维护对于目前线段树区间的答案,因为不这样维护修改是一段后/前缀,不可做。
之后我们感性理解一波肯定还要维护区间最大值,不然显然无法 upd,我们考虑两个区间合并时,左儿子信息可以继承而来,原因显然(真的显然吗),然后我们考虑右区间会减少多少,此时我们就是需要在意左区间的最大值对答案的影响,我们继续递归右区间,考察右区间的左区间和右区间的右区间,如果右区间的左区间的最大值已经大过了左区间的最大值,那么右区间的右区间可以直接接上,此处需要注意并非直接调用右区间的右区间的 dat, 而应该用右区间总的减去右区间的左区间的答案,然后递归计算右区间的左区间。反之右区间的左区间没有用,直接递归计算右区间的右区间的答案。我们发现每次最多递归一边,所以每次 upd 都会计算 \(\log n\) 次,而一共会 upd \(\log n\) 次,所以总复杂度为 \(\log^2 n\),就做完了。
// Problem: P4198 楼房重建
// Contest: Luogu
// URL: https://www.luogu.com.cn/problem/P4198
// Memory Limit: 125 MB
// Time Limit: 1000 ms
// Author: Air2011
//
// Powered by CP Editor (https://cpeditor.org)
#include<bits/stdc++.h>
using namespace std;
#define int long long
#define Air
namespace io{inline int read(){int x;cin>>x;return x;}inline void write(int x){cout<<x;}}
using namespace io;
int n, m;
const int N = 1e5 + 10;
const double eps = 1e-10;
int judg(double x, double y){
if(abs(x - y) <= eps) return 0;
if(x - eps > y) return 1;
return -1;
}
double h[N];
struct Segment{
int l, r;
double mx;
int dat;
}seg[N * 4];
void build(int p, int l, int r){
seg[p].l = l;
seg[p].r = r;
seg[p].mx = -1;
// cerr << p << ' ' << l << ' ' << r << endl;
if(seg[p].l == seg[p].r){
return ;
}
int mid = (l + r) >> 1;
build(p * 2, l, mid);
build(p * 2 + 1, mid + 1, r);
}
int ask(int p, double rmx){
if(seg[p].mx <= rmx) return 0;
if(seg[p].l == seg[p].r){
// cerr << p << ' ' << seg[p].mx << ' ' << rmx << ' ' << judg(seg[p].mx, rmx) << endl;
return seg[p].mx > rmx;
}
if(seg[p * 2].mx >= rmx){
return ask(p * 2, rmx) + seg[p].dat - seg[p * 2].dat;
}
else{
return ask(p * 2 + 1, rmx);
}
}
void upd(int p){
seg[p].mx = max(seg[p * 2].mx, seg[p * 2 + 1].mx);
// cerr << "ASK : " << p * 2 + 1 << endl;
seg[p].dat = seg[p * 2].dat + ask(p * 2 + 1, seg[p * 2].mx);
// cerr << "VALOF : " << p << ' ' << seg[p].dat << endl;
}
void change(int p, int x, double v){
if(seg[p].l == seg[p].r){
seg[p].mx = v;
// cerr << p << endl;
seg[p].dat = 1;
return ;
}
int mid = (seg[p].l + seg[p].r) >> 1;
if(x <= mid){
change(p * 2, x, v);
}
else{
change(p * 2 + 1, x, v);
}
// cerr << "UPD : " << p << endl;
upd(p);
}
signed main(){
#ifndef Air
freopen(".in","r",stdin);
freopen(".out","w",stdout);
#endif
ios::sync_with_stdio(false);
cin.tie(0);cout.tie(0);
n = read();
m = read();
build(1, 0, n);
change(1, 0, 0);
for(int i = 1; i <= m; i++){
int id = read();
cin >> h[id];
h[id] = h[id] * 1.0 / id;
change(1, id, h[id]);
cout << seg[1].dat - 1 << '\n';
}
return 0;
}

浙公网安备 33010602011771号